Подтвердить что ты не робот

Ошибка компилятора Intel 2015, уничтожение RAII не правильно, это ошибка, или я делаю что-то неправильно?

У меня есть тестовый пример, где у меня есть класс с 3 подобъектами (A, B и C), а второй подобъект B генерирует исключение во время построения. Поскольку я понимаю С++, компилятор должен перемотать конструкцию большого класса и уничтожить 1-й объект A, но не 2-й (B) или 3-й (C) объекты.

Я вижу, что если я использую "In-class initialization" первого объекта A, то вместо первого объекта A, который будет уничтожен, 3-й объект C будет уничтожен. Конечно, VERY BAD уничтожить объект, который еще не был создан! Если, например, 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

- обновить -

Раздел стандарт, который описывает, что должно произойти, это 15.2.3

Для объекта типа класса любой продолжительности хранения, инициализация или уничтожение прекращаются за счет исключения, деструктор вызывается для каждого из полностью сконструированных объектов подобъекты, т.е. для каждого подобъекта, для которого главный конструктор (12.6.2) завершил выполнение, и деструктор еще не начатое исполнение, за исключением того, что в случае Вариантные члены объединенного класса не уничтожаются. подобъекты уничтожаются в обратном порядке завершения их строительство. Такое разрушение секвенировано до ввода обработчик функции-try-block конструктора или деструктора, если любой.

4b9b3361

Ответ 1

Это определенно ошибка компилятора, и вы ответили на свой вопрос правильной ссылкой из стандарта: [except.ctor]/3, с акцентом:

Для объекта типа класса любой продолжительности хранения, инициализация или уничтожение которого завершается исключение, деструктор вызывается для каждого из объектов полностью построенных объектов, т.е. для каждого подобъект, для которого главный конструктор (12.6.2) завершил выполнение, а деструктор не но начатое исполнение, за исключением того, что в случае уничтожения варианты членов подобного типа не являются уничтожены. Субобъекты уничтожаются в обратном порядке завершения их строительства. такие разрушение секвенируется до ввода обработчика функции-try-блока конструктора или деструктора, если таковые имеются.

Где:

Главный конструктор - это первый вызванный конструктор в построении объекта (т.е. не является конструктором-мишенью для построения этих объектов).

C не был полностью построен - его главный конструктор еще даже не был вызван - поэтому его деструктор еще нельзя назвать.

Ответ 2

Intel подтвердила, что это проблема.

Я использовал компилятор

icpc (ICC) 15.0.2 20150121

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

https://software.intel.com/en-us/comment/1827356