I have some members that can't be initialized at construction time of the container class because the information to construct them is not available. At the moment I'm using std::unique_ptr to construct them later when the information becomes available.
The dynamic allocation/indirection is an unnecessary overhead as I know they will be constructed eventually. I could use std::optional, but I feel the semantics of std::optional will make the ones reading the code think the members are somehow optional and they might be missing which is not the case.
Is there any std library type that can hold a type for later construction with better semantics than std::optional?
EDIT: example code
struct Inner
{
Inner(int someValue)
: internalValue(someValue)
{}
int internalValue;
};
struct Outer
{
Outer(){/*...*/}
void createInner(int someValue)
{
assert(inner == nullptr);
inner = std::make_unique<Inner>(someValue);
}
// I would like to avoid the dynamic memory allocation here
std::unique_ptr<Inner> inner;
};
CodePudding user response:
std:::optional is what you are looking for, eg:
#include <optional>
struct Inner
{
Inner(int someValue)
: internalValue(someValue)
{}
int internalValue;
};
struct Outer
{
Outer(){/*...*/}
void createInner(int someValue)
{
inner = Inner(someValue);
}
std::optional<Inner> inner;
};
If you don't like how optional looks in your code, you can simply define an alias to give it a more suitable name for your situation, eg:
#include <optional>
struct Inner
{
Inner(int someValue)
: internalValue(someValue)
{}
int internalValue;
};
template<typename T>
using delayed_create = std::optional<T>;
struct Outer
{
Outer(){/*...*/}
void createInner(int someValue)
{
inner = Inner(someValue);
}
delayed_create<Inner> inner;
};
CodePudding user response:
You can just use a union and placement new.
The advantage of this method is that it is universal. With std::optional you will need a C 17 compiler while with this you can build with any C compiler ever known to manhood.
Example:
class Inner {
public:
Inner() = delete;
Inner( int val ) : a(val) {}
private:
int a;
};
class Outer {
Outer() {}
~Outer() {
if ( initialized ) {
inner.~Inner();
initialized = false;
}
}
Outer( const Outer& ) = delete; // TBI
Outer( Outer&& ) = delete; // TBI
Outer( const Outer&& ) = delete; // TBI
void create( int x ) {
if ( not initialized ) {
initialized = true;
new ((void*)&inner) Inner(x);
}
}
private:
bool initialized = false;
union {
Inner inner;
};
};
Code above not complete. Needs to fill in the copy/move constructors.
