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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7557153/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 17:07:03  来源:igfitidea点击:

Defining an object without calling its constructor in C++

c++classobjectconstructor

提问by Hannesh

In C++, I want to define an object as a member of a class like this:

在 C++ 中,我想将一个对象定义为这样的类的成员:

Object myObject;

However doing this will try to call it's parameterless constructor, which doesn't exist. However I need the constructor to be called after the containing class has done some initialising. Something like this.

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

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

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

}

采纳答案by Julian

Store a pointer to an Objectrather than an actual Object

存储指向一个Object而不是实际的指针Object

thus:

因此:

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

}

Don't forget to deleteit in the destructor. Modern C++ helps you there, in that you could use an auto_ptrshared_ptr rather than a raw memory pointer.

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

回答by bdonlan

Others have posted solutions using raw pointers, but a smart pointer would be a better idea:

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

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

This avoids the need to add a destructor, and implicitly forbids copying (unless you write your own operator=and MyClass(const MyClass &).

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

If you want to avoid a separate heap allocation, this can be done with boost's aligned_storageand placement new. Untested:

如果你想避免单独的堆分配,这可以通过 boostaligned_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();
  }
}

Or, if Objectis copyable (or movable), you can use boost::optional:

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

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

回答by Nim

If you have access to boost, there is a handy object that is provided called boost::optional<>- this avoids the need for dynamic allocation, e.g.

如果您可以访问 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;
};

回答by Joris Timmermans

You may also be able to rewrite your code to use the constructor initializer list, if you can move off the other initialization into constructors:

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

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

You need to be aware that following such a pattern will lead you to a path where you do a lot of work in constructors, which in turn leads to needing to grasp exception handling and safety (as the canonical way to return an error from a constructor is to throw an exception).

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

回答by jenkas

You can fully control the object construction and destruction by this trick:

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

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

Apply on your sample:

应用于您的样品:

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

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

}

Big advantage of this solution, is that it does not require any additional allocations, and object memory allocated as normal, but you have control when call to constructor.

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

Another sample link

另一个示例链接

回答by Sardathrion - against SE abuse

You can use a pointer (or a smart pointer) to do that. If you do not use a smart pointer, do make sure that your code free memory when the object is deleted. If you use a smart pointer, do not worry about it.

您可以使用指针(或智能指针)来做到这一点。如果您不使用智能指针,请确保您的代码在删除对象时释放内存。如果您使用智能指针,请不要担心。

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