Называется деструктор члена профсоюза

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деструктор?

18

Решение

В вашем примере, который вы предоставили 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

15

Другие решения

Ваш пример не скомпилируется. У профсоюзов по умолчанию удален деструктор. Потому что, конечно, какой деструктор должен называться? Конечно, вы не можете позвонить обоим. И нигде не хранится какая-либо информация о том, какой член был фактически построен Это зависит от вас, чтобы обеспечить правильный деструктор.

Вот вывод 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;
^
4

Вам всегда нужно вручную вызывать конструктор объектов в вашей структуре с нетривиальными типами.

Обычно вам всегда нужно также явно их конструировать. Кажется странным, что назначение здесь работает.

В случае сомнений, вы всегда можете проверить сборку, если вызваны деструкторы.

Сборка этого кода вызывает 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

1
По вопросам рекламы [email protected]