构造一个对象,将其传递给基础 class 构造函数,以控制其生命周期
Construct an object, pass it to the base class constructor keeping control of its lifetime
我需要根据以下要求从 class 基派生一个 class 子代:
- Class 基本构造函数接受对 class Foo.
对象的引用
- class Foo 的对象应该与 class Child 的对象具有相同的生命周期。
- Foo、Child 和 Base 的构造函数可以抛出,代码应该充分破坏到目前为止创建的内容。
- 代码是多线程的,可以同时调用child的多个构造函数
- Foo 没有复制构造函数,也没有默认构造函数。
(与How to remind a param passed to the base class constructor?有一些相似之处
然而异常安全几乎没有在上述问题中讨论)
在实现过程中遇到了以下困难:
一个。 class 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) ...
这会将临时引用传递给 class 基本构造函数(它甚至可以编译吗?),然后单独初始化 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 成员:
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 - 创建 另一个 class 拥有 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
- 因为它肯定会在 [= 之前构造16=]。
如果您因为某种原因觉得太冗长,您也可以使用 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)
{ }
};
我需要根据以下要求从 class 基派生一个 class 子代:
- Class 基本构造函数接受对 class Foo. 对象的引用
- class Foo 的对象应该与 class Child 的对象具有相同的生命周期。
- Foo、Child 和 Base 的构造函数可以抛出,代码应该充分破坏到目前为止创建的内容。
- 代码是多线程的,可以同时调用child的多个构造函数
- Foo 没有复制构造函数,也没有默认构造函数。
(与How to remind a param passed to the base class constructor?有一些相似之处 然而异常安全几乎没有在上述问题中讨论)
在实现过程中遇到了以下困难:
一个。 class 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) ...
这会将临时引用传递给 class 基本构造函数(它甚至可以编译吗?),然后单独初始化 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 成员:
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 - 创建 另一个 class 拥有 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
- 因为它肯定会在 [= 之前构造16=]。
如果您因为某种原因觉得太冗长,您也可以使用 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)
{ }
};