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

标签 c++ constructor

我需要根据以下要求从类 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/

相关文章:

c++ - 是否可以初始化 const Eigen 矩阵?

c++ - 应该如何构建基本的类层次结构?

python - 如何从 python 模块 (boost.python) 导入类?

c++ - 如何创建类似于 boost::lock_guard 的守卫

c++ - 初始化依赖于另一个类成员的类成员

c++ - 重载构造函数中的代码重复

c++ - 想通过使用带变量的构造函数来声明数组

C++ 类在另一个类中初始化,出现错误

c++ - 如何计算指针的哈希值?

c++ - mac osx 上未找到架构 x86_64 错误的符号