Я удивлен, что никто не упомянул полностью совместимое со стандартом C ++ решение с union
. В union
ни один конструктор, даже деструктор, не вызывается автоматически для членов. Даже если в союзе только один член. Все что нужно сделать "вручную":
конструктор можно вызвать через так называемое «размещение нового» (или из списка инициализации конструктора, введенного :
),
деструктор может быть вызван явным вызовом метода деструктора.
Демо-версия:
class MyObj {
int i;
public:
MyObj(int i_) : i(i_) { std::cout << i << " constructed" << std::endl; }
MyObj(MyObj const &src) : i(src.i + 100) { std::cout << src.i << " copied to new " << i << std::endl; }
~MyObj() { std::cout << i << " destroyed" << std::endl; }
};
class OptDestr {
bool callDestructor;
union { MyObj o; }; // Only allocated, but no constr/destr is called automatically
public:
// Constructor
OptDestr(int i, bool callDestructor_) : callDestructor(callDestructor_),
o(i) // calls MyObj constructor
{ }
// OR alternatively:
OptDestr(int i, bool callDestructor_) : callDestructor(callDestructor_) {
new (&o)MyObj(i); // placement new - does NOT allocate, just calls constructor
}
// Copy constructor
OptDestr(OptDestr const &src) : callDestructor(src.callDestructor),
o(src.o) // explicit call of MyObj copy-constructor
{ }
// OR alternatively:
OptDestr(OptDestr const &src) : callDestructor(src.callDestructor) {
new (&o)MyObj(src.o); // placement new - no allocation, just explicitly calls copy-constructor of MyObj
}
// Destructor
~OptDestr() {
if (callDestructor) o.~MyObj(); // explicit call of destructor
}
};
int main() {
OptDestr d1(1, false /*callDestructor*/);
OptDestr d1_copy(d1);
OptDestr d2(2, true /*callDestructor*/);
OptDestr d2_copy(d2);
}
Вывод программы следующий:
1 constructed
1 copied to new 101
2 constructed
2 copied to new 102
102 destroyed
2 destroyed
Вы можете видеть, что нет ни 1 destructed
, ни 101 destructed
. Я предполагаю, что типы типа std::Optional
реализованы аналогичным образом.