71

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(...); } } 
3
  • 4
    Why not using dynamic initialization? auto_ptr/shared_ptr? Commented Sep 26, 2011 at 15:07
  • 1
    Global scope or member of a class? Your code doesn't match your question. Commented Sep 26, 2011 at 15:08
  • What is wrong with it calling the default constructor then after your initialization you set it to your object you care about, exactly like your code does? Or just make it a pointer: Object* myObj; Commented Sep 26, 2011 at 15:08

8 Answers 8

44

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.

Sign up to request clarification or add additional context in comments.

8 Comments

If you do create a destructor, you should obey the rule of three.
@RomanKruglov • a std::unique_ptr is fine, as long as you also = delete the copy constructor and the assignment operator, or implement them to do the right thing.
You mean to delete myObject in the destructor of Object or Program?
@Eljay: Why would you need to = delete the copy constructor/assignment operator to use std::unique_ptr? My understanding is that, if any member of the class has a deleted copy constructor, the class's copy constructor/assignment operators are implicitly deleted (you'd have to write them explicitly if even a single unique_ptr is part of the instance state).
@Eljay: That's the point of what I was linking earlier program2 = program; will fail because simply by having a std::unique_ptr member (which deletes its own copy constructor/copy assignment), its own copy constructor/assignment is also deleted. Using = delete; explicitly is redundant; the compiler already deletes them (precisely to prevent the problem you're describing). The problem you're describing sounds like an issue with the old std::auto_ptr, which transferred ownership on copy; std::unique_ptr prevents that behavior.
|
25

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

1 Comment

Using your first suggestion, I get The text ">" is unexpected. It may be that this token was intended as a template argument list terminator but the name is not known to be a template.
8

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

Comments

6

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

2 Comments

I just came across with this problem. If i call the specified constructor in intialising list it works as a charm. If i don't, the default constructor will be called. I don't understand how the compiler knows that later on I initialize the object, because at the moment the program encounters the declarations of my object MyClass obj; there is no sign for the compiler to know "i wont call here the default constructor, i Shall wait until the initializing list"
@CătălinaSîrbu - I'm not entirely certain, but I'm guessing that maybe the order of the class declaration is making you think that's the order of initialization. The initializer list is actually done before anything else in the construction of the class, so it's useful to set things up that you will need later on in the constructor as well.
5

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

Comments

1

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.

Comments

0

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

Comments

0

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

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.