У меня есть тестовый пример, где у меня есть класс с 3 подобъектами (A
, B
и C
), а второй подобъект B
выдает исключение во время строительства. Поскольку я понимаю C++, компилятор должен перемотать конструкцию большого класса и уничтожить 1-й объект A
, но не 2-й (B
) или 3-й (C
) объектов.Ошибка компилятора Intel 2015, уничтожение RAII не правильно, это ошибка, или я делаю что-то неправильно?
Что я вижу в том, что если я использую «В классе инициализации» первого объекта A
, то вместо первого объекта A
получения разрушен, 3-й объект C
разрушается. Конечно, это ОЧЕНЬ ПЛОХО уничтожить объект, который еще не был построен! Если, например, C
был std:unique_ptr<T>
, он, вероятно, сигнализирует о нарушении сегментации, когда он пытается освободить указатель мусора.
Если я использую инициализацию члена старой школы, то эта проблема не возникает.
Я не вижу это с GCC 4.8
Вот код. Класс D
раскрывает ошибку. Класс E
должен иметь идентичную функцию, но не обнаруживает ошибку.
#include <iostream>
using namespace std;
struct A {
A(const string& x) : x_(x) { cout << "A::A()" << (void*)this <<endl; }
~A() { cout << "A::~A() " << (void*)this<< endl;}
string x_;
};
struct B {
B(const A& a) { cout << "B::B()" << endl; throw "dead"; }
~B() { cout << "B::~B()" << endl;}
};
struct C {
C() { cout << "C::C()" << endl; }
~C() { cout << "C::~C()" << endl;}
};
struct D {
A a{"foo"}; // "new school In-class initialization"
B b{a};
C c;
D() { cout <<"D::D()" << endl; }
~D() { cout <<"D::~D()" << endl; }
};
struct E {
A a;
B b;
C c;
E()
:a{"foo"} // "old school member initialization"
,b(a)
{ cout <<"E::E()" << endl; }
~E() { cout <<"E::~E()" << endl; }
};
int main()
{
try {
D d;
}
catch(...)
{
cout << "got exception" << endl;
}
try {
E e;
}
catch(...)
{
cout << "got exception" << endl;
}
return 0;
}
Вот выход. Я ожидаю увидеть A
построенный, B
частично построенный, затем броски, затем A
уничтожен, но это не то, что я вижу для случая D
.
$ icpc -std=c++11 test.cpp
$ ./a.out
A::A()0x7fffe0a5ee90
B::B()
C::~C()
got exception
A::A()0x7fffe0a5eea0
B::B()
A::~A() 0x7fffe0a5eea0
got exception
- обновление -
В разделе standard, который описывает то, что должно произойти, 15.2.3
Для объекта класса типа любой продолжительности хранения которого инициализации или уничтожение прекращается с помощью исключения, для каждого из полностью созданных объектов вызывается деструктор , то есть для каждого подобъекта, для которого главный конструктор (12.6.2) завершил выполнение, а деструктор имеет , еще не начатое выполнение, за исключением того, что в случае уничтожения члены варианта типа объединения не уничтожаются. Субъекты уничтожаются в порядке, обратном порядку завершения строительства . Такое разрушение секвенируется до ввода обработчика блока try-try конструктора или деструктора, если любой.
Для тех, кто заинтересован, наличия 'Try/catch' обертки делает разницу в стек разматывании и несоответствия в компиляторах: см http://stackoverflow.com/questions/22137693/ if-initialization-or-destroy-is -contininated-by-the-exception-which-is-not-hand –