我需要根据以下要求从类 Base 派生一个类 Child:
- Class Base 构造函数接受对 Foo 类对象的引用。
- Foo 类的对象应该与 Child 类的对象具有相同的生命周期。
- Foo、Child 和 Base 的构造函数可以抛出,代码应该充分破坏到目前为止创建的内容。
- 代码是多线程的,可以同时调用child的多个构造函数
- Foo 没有复制构造函数,也没有默认构造函数。
(与How to remind a param passed to the base class constructor?有一些相似之处 然而异常安全几乎没有在上述问题中讨论)
在实现过程中遇到了以下困难:
一个。让类 Foo 的对象成为 Child 的成员似乎很自然
class Base {
public:
Base(Foo& foo);
};
class Child: public Base {
public:
Child(int par);
private:
Foo m_foo;
};
但是,现在如何在 Child 构造函数中初始化它?
Child::Child(int par):
Base(Foo(par)),
m_Foo(par) ...
这会将临时引用传递给类 Base Constructor(它甚至会编译吗?),然后单独初始化 m_Foo。这很糟糕。
如果不是因为需求#4 和#5,我可以在调用 Base 时使用静态方法共同构造 Foo,然后将其传递给 m_Foo:
Foo Child::s_Helper(int par) {
if (!s_FooConstructed) {
s_Foo = Foo(par);
s_FooConstructed = true;
}
return s_Foo;
}
我喜欢使用 unique_ptr 或 shared_ptr 作为子类成员:
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;
}
然而,这里的 m_Foo 并没有在调用 x_FooHelper 时被构建... 与 shared_ptr 相同
我可以创建一个指针:
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;
}
但是在这里,如果 Base 构造函数抛出,Foo 已经被创建,并且它不会被销毁,因为它由原始指针 (m_Foo) 保存 ~Child 也不会被调用。我能做什么?
最佳答案
使用 Base-from-Member Idiom - 创建另一个类,它拥有Foo
作为Child
的第一个基数:
class Base {
public:
Base(Foo& foo);
};
struct FooOwner {
FooOwner(int par)
: m_foo(par)
{ }
Foo m_foo;
};
class Child
: private FooOwner // first, so Foo is initialized
, public Base // before Base
{
public:
Child(int par)
: FooOwner(par)
, Base(FooOwner::m_foo)
{
/* something else */
}
};
Foo
的生命周期仍然与 Child
相关联,您可以安全地将对它的引用传递给 Base
- 因为它肯定将在 Base
之前构造。
如果您出于某种原因觉得太冗长,您也可以使用 boost::base_from_member
实现同样的目标:
class Child
: private boost::base_from_member<Foo>
, public Base
{
typedef boost::base_from_member<Foo> FooOwner;
Child(int par)
: FooOwner(par)
, Base(FooOwner::member)
{ }
};
关于c++ - 构造一个对象,将其传递给基类构造函数以控制其生命周期,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30519006/