I need to derive a class Child from the class Base with the following requirements:
- Class Base constructor accepts a reference to an object of class Foo.
- Objects of class Foo should have same lifetime as an object of class Child.
- Constructors of Foo, Child and Base can throw, code should adequately destruct what is created so far.
- Code is multi-threaded, many constructors of child can be called at the same time
- Foo does not have copy constructor, does not have default constructor.
(there are some similarities with How to remind a param passed to the base class constructor? however exception-safety is almost not discussed in the above mentioned question)
While implementing it, I encountered the following difficulties:
A. It seems natural to have object of class Foo to be a member of Child
class Base {
public:
Base(Foo& foo);
};
class Child: public Base {
public:
Child(int par);
private:
Foo m_foo;
};
However, how do I initialize it now in Child constructor?
Child::Child(int par):
Base(Foo(par)),
m_Foo(par) ...
This will pass a ref to temporary to class Base Constructor (will it even compile?) and then initialize m_Foo separately. This is bad.
If not for requirements #4 and #5, I could have used a static method co construct Foo when Base is called and then pass it to m_Foo:
Foo Child::s_Helper(int par) {
if (!s_FooConstructed) {
s_Foo = Foo(par);
s_FooConstructed = true;
}
return s_Foo;
}
I would love to use unique_ptr or shared_ptr as Child class member:
class Child: public Base {
public:
Child(int par);
private:
unique_ptr<Foo> m_Foo;
bool m_IsFooConstructed;
unique_ptr<Foo> x_FooHelper(int par);
};
Child::Child(int par):
Base(x_FooHelper(par)),
m_Foo(x_FooHelper(par))
{}
unique_ptr <Foo> Child::x_FooHelper(int par)
{
if(!m_FooConstructed) {
m_Foo.reset(new Foo(par)); ///< Problem here
m_FooConstructed = true;
}
return m_Foo;
}
however, here m_Foo is not constructed at the time x_FooHelper is called... same with shared_ptr
I can create a pointer instead:
class Child: public Base {
public:
Child(int par);
private:
Foo* m_Foo;
bool m_IsFooConstructed;
Foo* x_FooHelper(int par);
};
Child::Child(int par):
Base(*x_FooHelper(par)),
m_Foo(x_FooHelper(par))
{}
Foo* Child::x_FooHelper(int par)
{
if(!m_FooConstructed) {
m_Foo = new Foo(par);
m_FooConstructed = true;
}
return m_Foo;
}
However here, if Base constructor throws, Foo is already created, and it will not be destroyed as it is kept by the raw pointer (m_Foo) ~Child will also not be called. What can I do?