You can wrap the member in a union.
#include <iostream>
using std::cout;
struct A {
A() { cout << "A's constructor was called!\n"; }
};
struct B {
union { A member; };
B() {
cout << "B's constructor was called!\n";
}
};
int main() {
B b; // will only print "B's constructor was called!"
}
member will not have its constructor or destructor called.
If you want to have multiple members be uninitialized, create a separate union for each of them. So for example if you wanted B to hold additional members of any types C, D, E , you'd declare it as such:
struct B {
union { A a; };
union { C c; };
union { D d; };
union { E e; };
// ... and so on
B() { cout << "B's constructor was called!\n"; }
};
It's also ok to have multiple members of the same type, just make sure each member is in its own union:
struct B {
union { A x; };
union { A y; };
union { A z; };
// ... and so on
B() { cout << "B's constructor was called!\n"; }
};
Whenever you want to manually initialize any members declared like this, you may do so using the placement-new syntax. The placement-new syntax looks like this: new (&variable) Type(arguments to the constructor); This might look a little weird so I will show an example below.
Going back to the simple case, here's an example where B has a method initializeA to initialize member, using the placement-new syntax.
#include <iostream>
using std::cout;
struct A {
A() { cout << "A's constructor was called!\n"; }
};
struct B {
union { A member; };
B() {
cout << "B's constructor was called!\n";
}
void initializeA() {
new (&member) A();
}
};
int main() {
B b; // will only print "B's constructor was called!"
b.initializeA(); // will print "A's constructor was called!"
}
The placement-new syntax allows you to pass arguments to the constructor.
Finally if you have initialized some member, it's important to remember that you have to do the work of calling the destructor yourself!
Here's an example where B calls the destructor of A to destroy it.
#include <iostream>
using std::cout;
struct A {
A() { cout << "A's constructor was called!\n"; }
A() { cout << "A's destructor was called!\n"; }
};
struct B {
union { A member; };
B() {
cout << "B's constructor was called!\n";
}
void initializeA() {
new (&member) A();
}
void destroyA() {
A::~A();
}
};
int main() {
B b; // will only print "B's constructor was called!"
b.initializeA(); // will print "A's constructor was called!"
}
But this is a little error-prone since you should only call the destructor of A if you have already initialized A. Perhaps B would have a variable to keep track of this, making it a little safer. And put it in the destructor of B so that we won't forget.
#include <iostream>
using std::cout;
struct A {
A() { cout << "A's constructor was called!\n"; }
~A() { cout << "A's destructor was called!\n"; }
};
struct B {
union { A member; };
bool initialized;
B(): initialized(false) {
cout << "B's constructor was called!\n";
}
void initializeA() {
// constructor should only be called if A is uninitialized
if (!initialized) {
new (&member) A();
initialized = true;
}
}
void destroyA() {
// the destructor should only be called if A is *initialized*
if (initialized) {
A::~A();
initialized = false;
}
}
~B() {
destroyA();
}
};
int main() {
B b; // will only print "B's constructor was called!"
b.initializeA(); // will print "A's constructor was called!"
} // will print "A's destructor was called!" in B's destructor
I hope this was helpful. It's interesting how much you can do with the control C++ gives you over things like this.