2011-09-26 238 views
33

在C++中,我希望定義一個對象作爲這樣一個類的成員:定義對象,而不調用構造函數在C++

Object myObject; 

但是這樣做會嘗試調用它的參數的構造函數,它沒有按不存在。不過,我需要在包含類完成一些初始化之後調用構造函數。像這樣的東西。

class Program 
{ 
public: 
    Object myObject; //Should not try to call the constructor or do any initializing 
    Program() 
    { 
     ... 

     //Now call the constructor 
     myObject = Object(...); 
    } 

} 
+4

爲什麼不使用動態初始化? auto_ptr的/ shared_ptr的? – qehgt

+1

全球範圍或班級成員?您的代碼與您的問題不符。 –

+0

調用默認構造函數時會出現什麼問題,然後在初始化後將其設置爲您關心的對象,就像您的代碼一樣?或者只是讓它成爲一個指針:'Object * myObj;' – Chad

回答

20

商店的指針Object,而不是實際Object

這樣的:

class Program 
{ 
public: 
    Object* myObject; // Will not try to call the constructor or do any initializing 
    Program() 
    { 
     //Do initialization 
     myObject = new Object(...); // Initialised now 
    } 

} 

不要忘記delete它在析構函數。現代C++可以幫助你,因爲你可以使用一個 auto_ptr shared_ptr而不是一個原始的內存指針。

+4

如果你創建了一個析構函數,你應該遵守三條規則。 – Sardathrion

+0

爲什麼不'std :: unique_ptr'而不是共享? –

+0

@RomanKruglov•一個'std :: unique_ptr'沒問題,只要你還''刪除'拷貝構造函數和賦值操作符,或者實現它們來做正確的事情。 – Eljay

1

您可以使用指針(或智能指針)來做到這一點。如果您不使用智能指針,請確保在刪除對象時確保您的代碼可用內存。如果您使用智能指針,請不要擔心。

class Program 
{ 
public: 
    Object * myObject; 
    Program(): 
     myObject(new Object()) 
    { 
    } 
    ~Program() 
    { 
     delete myObject; 
    } 
    // WARNING: Create copy constructor and = operator to obey rule of three. 
} 
16

其他人使用原始指針發佈的解決方案,而是一個智能指針將是一個更好的主意:

class MyClass { 
    std::unique_ptr<Object> pObj; 
    // use boost::scoped_ptr for older compilers; std::unique_ptr is a C++0x feature 
public: 
    MyClass() { 
    // ... 
    pObj.reset(new Object(...)); 
    pObj->foo(); 
    } 
    // Don't need a destructor 
}; 

這避免了需要添加一個析構函數,並含蓄地禁止複製(除非你寫你的。自己operator=MyClass(const MyClass &)

如果你想避免單獨堆分配,這可以用做升壓轉換器的aligned_storage和安置新的未經檢驗:

template<typename T> 
class DelayedAlloc : boost::noncopyable { 
    boost::aligned_storage<sizeof(T)> storage; 
    bool valid; 
public: 
    T &get() { assert(valid); return *(T *)storage.address(); } 
    const T &get() const { assert(valid); return *(const T *)storage.address(); } 

    DelayedAlloc() { valid = false; } 

    // Note: Variadic templates require C++0x support 
    template<typename Args...> 
    void construct(Args&&... args) 
    { 
    assert(!valid); 
    new(storage.address()) T(std::forward<Args>(args)...); 
    valid = true; 
    } 

    void destruct() { 
    assert(valid); 
    valid = false; 
    get().~T(); 
    } 

    ~DelayedAlloc() { if (valid) destruct(); } 
}; 

class MyClass { 
    DelayedAlloc<Object> obj; 
public: 
    MyClass() { 
    // ... 
    obj.construct(...); 
    obj.get().foo(); 
    } 
} 

或者,如果Object是可複製(或移動),您可以使用boost::optional

class MyClass { 
    boost::optional<Object> obj; 
public: 
    MyClass() { 
    // ... 
    obj = Object(...); 
    obj->foo(); 
    } 
}; 
+0

使用你的第一個建議,我得到 '文本「>」是意外​​的。它可能是這個標記是作爲一個模板參數列表結束符,但名字不知道是模板 – Anonymous

5

如果你有機會獲得提升,還有就是提供了一個名爲boost::optional<>一個方便的對象 - 這避免了需要動態分配,例如

class foo 
{ 
    foo() // default std::string ctor is not called.. 
    { 
    bar = boost::in_place<std::string>("foo"); // using in place construction (avoid temporary) 
    } 
private: 
    boost::optional<std::string> bar; 
}; 
2

您還可能能夠重寫代碼使用構造函數初始化列表,如果你能在其他初始化移出到構造函數:

class MyClass 
    { 
    MyObject myObject; // MyObject doesn't have a default constructor 
    public: 
    MyClass() 
     : /* Make sure that any other initialization needed goes before myObject in other initializers*/ 
     , myObject(/*non-default parameters go here*/) 
     { 
     ... 
     } 
    }; 

您需要注意的是以下這樣的模式會導致你在構造函數中做很多工作,這又導致需要掌握異常處理和安全性(正如從構造函數返回錯誤的典型方法是拋出異常)。

相關問題