gpt4 book ai didi

c++ - 构造一个对象,将其传递给基类构造函数以控制其生命周期

转载 作者:行者123 更新时间:2023-11-28 00:15:38 25 4
gpt4 key购买 nike

我需要根据以下要求从类 Base 派生一个类 Child:

  1. Class Base 构造函数接受对 Foo 类对象的引用。
  2. Foo 类的对象应该与 Child 类的对象具有相同的生命周期。
  3. Foo、Child 和 Base 的构造函数可以抛出,代码应该充分破坏到目前为止创建的内容。
  4. 代码是多线程的,可以同时调用child的多个构造函数
  5. 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/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com