Defining an object without calling its constructor in C++

C++ClassObjectConstructor

C++ Problem Overview


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

C++ Solutions


Solution 1 - C++

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.

Solution 2 - C++

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

Solution 3 - C++

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

Solution 4 - C++

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

Solution 5 - C++

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

Solution 6 - C++

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

Solution 7 - C++

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.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionHanneshView Question on Stackoverflow
Solution 1 - C++JulianView Answer on Stackoverflow
Solution 2 - C++bdonlanView Answer on Stackoverflow
Solution 3 - C++jenkasView Answer on Stackoverflow
Solution 4 - C++NimView Answer on Stackoverflow
Solution 5 - C++Joris TimmermansView Answer on Stackoverflow
Solution 6 - C++Sardathrion - against SE abuseView Answer on Stackoverflow
Solution 7 - C++CylemonsView Answer on Stackoverflow