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

时间:2011-09-26 15:04:49

标签: c++ class object constructor

在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(...);
   }

}

7 个答案:

答案 0 :(得分:23)

存储指向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而不是原始内存指针。

答案 1 :(得分: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
};

这避免了添加析构函数的需要,并且隐式禁止复制(除非您编写自己的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();
  }
}

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

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

答案 2 :(得分: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;
};

答案 3 :(得分:4)

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

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*/)
      {
      ...
      }
  };

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

答案 4 :(得分:0)

您可以使用指针(或智能指针)来执行此操作。如果不使用智能指针,请确保在删除对象时代码释放内存。如果您使用智能指针,请不要担心。

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

答案 5 :(得分:0)

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

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

申请样品:

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

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

}

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

Another sample link

答案 6 :(得分:0)

涉及匿名联合和新放置的技巧

这类似于jenkas的回答,但更直接

class Program
{
public:
   union{
   Object myObject;
   }; //being a union member in this case prevents the compiler from attempting to call the (undefined) default constructor
   
   Program()
   {
      ...

      //Now call the constructor
      new (&myObject) Object(...);
   }
   ~Program()
   {
      myobject.~Object(); //also make sure you explicitly call the object's destructor
   }

}

无论如何,现在您必须显式定义所有特殊成员函数,因为编译器会默认将其删除。