Уничтожение возвращаемого значения при исключении деструктора - PullRequest
0 голосов
/ 06 ноября 2018

У меня есть следующий код:

#include <stdexcept>
#include <iostream>

struct ok {
    int _n;
    ok(int n) : _n(n) { std::cerr << "OK" << n << " born" << std::endl; }
    ~ok() {  std::cerr << "OK" << _n << " gone" << std::endl; }
};

struct problematic {
    ~problematic() noexcept(false) { throw std::logic_error("d-tor exception"); }
};

ok boo() {
    ok ok1{1};
    problematic p;
    ok ok2{2};
    return ok{3}; // Only constructor is called...
}

int main(int argc, char **argv) {
    try {boo();} catch(...) {}
}

Я вижу, что деструктор ok {3} не вызывается, вывод:

 OK1 born
 OK2 born
 OK3 born
 OK2 gone
 OK1 gone

Это ожидаемое поведение для C ++ 14?

правок:

Компиляция с gcc 6.3

1 Ответ

0 голосов
/ 06 ноября 2018

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

В соответствии с сообщениями о дефектах на open-std.org они знали, что реализации (GCC и Clang) ошибались в этом уже в 2015-09-28 , Но предлагаемое решение было только в феврале 2016 года, и компиляторы (GCC и Clang) еще не включили это исправление.

Предлагаемое решение (февраль 2016 года):

Изменить пункт 18.2 [кроме объекта] следующим образом:
Деструктор вызывается для каждого автоматического объекта типа класса, созданного, но еще не уничтоженного, поскольку был введен блок try. Если во время уничтожения временных или локальных переменных для оператора return выдается исключение (9.6.3 [stmt.return]), также вызывается деструктор для возвращаемого объекта (если есть). Объекты уничтожаются в порядке, обратном завершению их строительства. [Пример:

  struct A { };

  struct Y { ~Y() noexcept(false) { throw 0; } };

  A f() {
    try {
      A a;
      Y y;
      A b;
      return {};   // #1
    } catch (...) {
    }
    return {};     // #2
  }

На # 1 создается возвращаемый объект типа A. Затем локальная переменная b уничтожается (9.6 [stmt.jump]). Затем локальная переменная y уничтожается, вызывая раскручивание стека, что приводит к уничтожению возвращаемого объекта и последующему уничтожению локальной переменной a. Наконец, возвращаемый объект снова создается в # 2. - конец примера]

Были обнаружены ошибки, связанные с этой проблемой, в GCC и Clang .

Комментарии к отчету об ошибках GCC указывают, что это явно ошибка.

Джонатан Уэйкли комментарии:

Сейчас 2013, поэтому разумно не возвращать по значению, если ваш деструктор может бросить.

И еще один пользователь:

Да, я заметил, и у Clang также была обнаружена ошибка, которая длилась годами. Тем не менее, поведение не так.

...