Ответ 1
В вашем примере, который вы предоставили str
, не будет разрушен. Стандартные состояния в [class.union]/2
Объединение может иметь функции-члены (включая конструкторы и деструкторы), но не виртуальные (10.3) функции. Союз не должен иметь базовые классы. Объединение не должно использоваться в качестве базового класса. Если объединение содержит нестатический элемент данных ссылочного типа, программа плохо сформирована. Не более чем один нестатический член данных объединения может иметь бит-или-равный-инициализатор. [ Примечание: если какой-либо нестатический член данных объединения имеет нетривиальный конструктор по умолчанию (12.1), конструктор копирования (12.8), конструктор перемещения (12.8), оператор назначения копирования (12.8), оператор присваивания перемещения ( 12.8) или деструктор (12.4), соответствующая членская функция объединения должна быть предоставлена пользователем или она будет неявно удалена (8.4.3) для объединения. - end note]
акцент мой
Так как оба str
и vec
имеют специальные функции-члены, которые не являются тривиальными, вам нужно будет предоставить их для объединения самостоятельно.
Заметьте, что в соответствии с комментариями bogdan ниже пустого деструктора недостаточно. В [class.union]/8 имеем
[...] Если X является объединением, его вариантными членами являются нестатические элементы данных, [...]
Таким образом, все члены этого союза являются вариантами. Тогда, если мы посмотрим на [class.dtor]/8, имеем
После выполнения тела деструктора и уничтожения любых автоматических объектов, выделенных в теле, деструктор класса X вызывает деструкторы для Xs прямых невариантных нестатических членов данных [...]
Таким образом, деструктор не будет автоматически уничтожать членов объединения, поскольку они являются вариантами.
Вы можете сделать tagged union, например kennytm делает здесь
struct TU { int type; union { int i; float f; std::string s; } u; TU(const TU& tu) : type(tu.type) { switch (tu.type) { case TU_STRING: new(&u.s)(tu.u.s); break; case TU_INT: u.i = tu.u.i; break; case TU_FLOAT: u.f = tu.u.f; break; } } ~TU() { if (tu.type == TU_STRING) u.s.~string(); } ... };
Который гарантирует, что правильный член уничтожен, или просто используйте std::variant
или boost::variant