C ++ 11 позволил использовать стандартные типы макетов в union
: Член Союза имеет пользовательский конструктор
Мой вопрос: гарантированно ли будет вызван пользовательский деструктор, когда union
выходит за рамки?
Насколько я понимаю, мы должны вручную разрушить и построить при переключении: http://en.cppreference.com/w/cpp/language/union#Explanation
Но как насчет примера, подобного этому:
{
union S { string str;
vector<int> vec;
~S() {} } s = { "Hello, world"s };
}
когда s
выходит из области видимости, я просочился в память строки, выделенной в куче, потому что я не вызывал string
деструктор?
В вашем примере, который вы предоставили str
не будет разрушен. Стандарт заявляет в [class.union] / 2
Объединение может иметь функции-члены (включая конструкторы и деструкторы), но не виртуальные (10.3) функции. У союза не должно быть базовых классов. Союз не должен использоваться в качестве базового класса. Если объединение содержит нестатический член данных ссылочного типа, программа является некорректной. Не более одного нестатического члена данных объединения может иметь инициализатор с фигурной или равной скобкой. [ Примечание. Если какой-либо элемент нестатических данных объединения имеет нетривиальный конструктор по умолчанию (12.1), конструктор копирования (12.8), конструктор перемещения (12.8), оператор назначения копирования (12.8), оператор назначения перемещения (12.8) или деструктор (12.4), соответствующая функция-член объединения должна быть предоставлена пользователем, или она будет неявно удалена (8.4.3) для объединения. — конец примечания ]
акцент мой
Так как оба str
а также vec
иметь специальные функции-члены, которые не являются тривиальными, вам нужно будет предоставить их для объединения самостоятельно.
Обратите внимание, что согласно Богдана комментариев под пустым деструктором недостаточно. В [class.union] / 8 мы имеем
[…] Если X является объединением, его вариантные члены являются нестатическими членами данных; […]
Таким образом, все члены этого союза являются вариантами. Тогда, если мы посмотрим на [class.dtor] / 8, мы имеем
После выполнения тела деструктора и уничтожения любых автоматических объектов, размещенных в теле, деструктор для класса X вызывает деструкторы для прямых не вариантных нестатических элементов данных X […]
Таким образом, деструктор не будет автоматически уничтожать членов союза, поскольку они являются вариантами.
Вы могли бы сделать помеченный союз лайк 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
Ваш пример не скомпилируется. У профсоюзов по умолчанию удален деструктор. Потому что, конечно, какой деструктор должен называться? Конечно, вы не можете позвонить обоим. И нигде не хранится какая-либо информация о том, какой член был фактически построен Это зависит от вас, чтобы обеспечить правильный деструктор.
Вот вывод GCC при попытке скомпилировать ваш фрагмент кода:
In function ‘int main()’:
error: use of deleted function ‘main()::<anonymous union>::~<constructor>()’
vector<int> vec; } s = { "Hello, world"s };
^
note: ‘main()::<anonymous union>::~<constructor>()’ is implicitly deleted because the default definition would be ill-formed:
union { string str;
^
Вам всегда нужно вручную вызывать конструктор объектов в вашей структуре с нетривиальными типами.
Обычно вам всегда нужно также явно их конструировать. Кажется странным, что назначение здесь работает.
В случае сомнений, вы всегда можете проверить сборку, если вызваны деструкторы.
Сборка этого кода вызывает basic_string
конструктор, но не деструктор. Таким образом, у вас будут утечки здесь.
using namespace std;
int main(int argc, char** argv){
union S { string str;
vector<int> vec;
~S() {} } s = { "Hello, world"s };
}
ссылка для просмотра сборки: https://godbolt.org/g/wKu3vf