定义一个对象而不用C++调用它的构造函数

Han*_*esh 45 c++ constructor class object

在C++中,我想将对象定义为类的成员,如下所示:

Object myObject;
Run Code Online (Sandbox Code Playgroud)

但是,这样做会尝试调用它的无参数构造函数,它不存在.但是我需要在包含类完成初始化之后调用构造函数.像这样的东西.

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

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

}
Run Code Online (Sandbox Code Playgroud)

Jul*_*ian 24

存储指向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
   }

}
Run Code Online (Sandbox Code Playgroud)

不要忘记delete它在析构函数中.现代C++可以帮助您,因为您可以使用auto_ptr shared_ptr而不是原始内存指针.

  • 如果你创建了一个析构函数,你应该遵守三个规则. (5认同)

bdo*_*lan 15

其他人已经使用原始指针发布了解决方案,但智能指针将是一个更好的主意:

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
};
Run Code Online (Sandbox Code Playgroud)

这避免了添加析构函数的需要,并且隐式禁止复制(除非你自己写operator=MyClass(const MyClass &).

如果您想避免单独的堆分配,可以使用boost aligned_storage和placement new 来完成.未经测试:

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();
  }
}
Run Code Online (Sandbox Code Playgroud)

或者,如果Object是可复制的(或可移动的),您可以使用boost::optional:

class MyClass {
  boost::optional<Object> obj;
public:
  MyClass() {
    // ...
    obj = Object(...);
    obj->foo();
  }
};
Run Code Online (Sandbox Code Playgroud)


Evg*_*tov 7

你可以通过这个技巧完全控制对象的构造和销毁:

template<typename T>
struct DefferedObject
{
    DefferedObject(){}
    ~DefferedObject(){ value.~T(); }
    template<typename...TArgs>
    void Construct(TArgs&&...args)
    {
        new (&value) T(std::forward<TArgs>(args)...);
    }
public:
    union
    {
        T value;
    };
};
Run Code Online (Sandbox Code Playgroud)

应用于您的样品:

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

      //Now call the constructor
      myObject.Construct(....);
   }

}
Run Code Online (Sandbox Code Playgroud)

这个解决方案的一大优点是它不需要任何额外的分配,并且正常分配对象内存,但是你可以控制调用构造函数。

另一个示例链接


Jor*_*ans 6

如果您可以将其他初始化转移到构造函数中,您也可以重写代码以使用构造函数初始化器列表:

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*/)
      {
      ...
      }
  };
Run Code Online (Sandbox Code Playgroud)

您需要注意,遵循这样的模式将导致您在构造函数中做大量工作,这反过来又导致需要掌握异常处理和安全性(作为从构造函数返回错误的规范方法)是抛出异常)。


Nim*_*Nim 5

如果您有权访问boost,则会提供一个被称为的方便对象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;
};
Run Code Online (Sandbox Code Playgroud)