在C++中定义对象而不调用其构造函数

u3r8eeie  于 2023-04-08  发布在  其他
关注(0)|答案(8)|浏览(220)

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

}
jutyujz0

jutyujz01#

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

9rbhqvlz

9rbhqvlz2#

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

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

uplii1fm3#

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

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

3duebb1j

3duebb1j4#

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

inb24sb25#

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

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

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

yhqotfr8

yhqotfr86#

你可以使用一个指针(或智能指针)来实现。如果你不使用智能指针,确保你的代码在对象被删除时释放内存。如果你使用智能指针,不用担心它。

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

vu8f3i0k7#

匿名联合和放置new的技巧

这与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
   }

}

然而,问题是现在你必须显式定义所有特殊成员函数,因为编译器会在默认情况下删除它们。

xjreopfe

xjreopfe8#

您可以通过使用union
联合的成员未初始化
尝试创建一个联盟

template <typename T>
union uninitialized_value_of
{ T value; };

创建一个uninitialized_value_of的对象,并将其引用到它的成员value

示例

class Program
{
    uninitialized_value_of<Object> MyObject;
    //Rest of your class
    //...
}

相关问题