2011-09-26 243 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*/) 
     { 
     ... 
     } 
    }; 

您需要注意的是以下这样的模式会导致你在构造函数中做很多工作,这又导致需要掌握异常处理和安全性(正如从构造函数返回错误的典型方法是抛出异常)。

相关问题