簡體   English   中英

構造一個對象,並將其傳遞給基類構造函數,以控制其生命周期

[英]Construct an object, pass it to the base class constructor keeping control of its lifetime

我需要從Base類派生一個Child類,並具有以下要求:

  1. Class Base構造函數接受對Foo類的對象的引用。
  2. Foo類的對象應與Child類的對象具有相同的生存期。
  3. Foo,Child和Base的構造函數可能會拋出,代碼應充分破壞到目前為止所創建的內容。
  4. 代碼是多線程的,可以同時調用child的許多構造函數
  5. Foo沒有復制構造函數,沒有默認構造函數。

(與如何提醒傳遞給基類構造函數的參數有些相似之處;但是在上述問題中幾乎沒有討論異常安全性)

在實施它時,我遇到了以下困難:

答:讓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) ...

這會將ref傳遞給臨時類Base構造函數(它甚至可以編譯嗎?),然后分別初始化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用作Child類成員:

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;
}

但是,這里在調用x_FooHelper時未構造m_Foo ...與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成語 -創建另一個擁有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)
    { }
};

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM