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

发布于 2024-12-06 20:05:41 字数 386 浏览 0 评论 0原文

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

}

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

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

}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

泡沫很甜 2024-12-13 20:05:41

存储指向对象而不是实际对象的指针

,因此:

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

}

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

Store a pointer to an Object rather than an actual 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 delete it in the destructor. Modern C++ helps you there, in that you could use an auto_ptr shared_ptr rather than a raw memory pointer.

一城柳絮吹成雪 2024-12-13 20:05:41

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

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 和放置 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();
  }
};

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 &).

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

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 Object is copyable (or movable), you can use boost::optional:

class MyClass {
  boost::optional<Object> obj;
public:
  MyClass() {
    // ...
    obj = Object(...);
    obj->foo();
  }
};
夏雨凉 2024-12-13 20:05:41

您可以通过以下技巧完全控制对象的构造和销毁:

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

}

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

另一个示例链接

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

柠北森屋 2024-12-13 20:05:41

如果您可以将其他初始化移至构造函数中,您还可以重写代码以使用构造函数初始值设定项列表:

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 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).

青衫负雪 2024-12-13 20:05:41

如果您有权访问 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;
};

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.

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;
};
一身软味 2024-12-13 20:05:41

涉及匿名联合和放置 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
   }

}

,但要注意的是,现在您必须显式定义所有特殊成员函数,因为编译器将默认删除它们。

A trick that involves anonymous union and placement new

this is similar to jenkas' answer but more direct

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
   }

}

however the catch is that now you must explicitly define all the special member functions as the compiler will delete them by default.

枕头说它不想醒 2024-12-13 20:05:41

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

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

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.
}
梦幻之岛 2024-12-13 20:05:41

您可以通过使用 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
    //...
}

You can do this by using an union

Members of an union are uninitialized

Try creating an union

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

Then whenever you want to get an uninitialized value. Create an object of uninitialized_value_of with the type you want and take the reference to its member value

Example

class Program
{
    uninitialized_value_of<Object> MyObject;
    //Rest of your class
    //...
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文