Reputation: 7488
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(...);
}
}
Upvotes: 70
Views: 49242
Reputation: 423
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
class Program
{
uninitialized_value_of<Object> MyObject;
//Rest of your class
//...
}
Upvotes: 0
Reputation: 11
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.
Upvotes: 1
Reputation: 971
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.
Upvotes: 8
Reputation: 2061
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.
Upvotes: 44
Reputation: 10978
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).
Upvotes: 6
Reputation: 33655
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;
};
Upvotes: 5
Reputation: 231163
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();
}
};
Upvotes: 25
Reputation: 18246
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.
}
Upvotes: 0