Раздел 18.8.1 [исключение]/p1 определяет:
namespace std {
class exception {
public:
exception() noexcept;
exception(const exception&) noexcept;
exception& operator=(const exception&) noexcept;
virtual ~exception();
virtual const char* what() const noexcept;
};
}
т.е. конструктор копирования и назначение копии std::exception должны быть noexcept
, и это можно проверить с помощью:
static_assert(std::is_nothrow_copy_constructible<std::exception>::value, "");
static_assert(std::is_nothrow_copy_assignable<std::exception>::value, "");
т.е. если реализация не делает эти элементы исключенными, то она не соответствует требованиям в этом отношении.
Точно так же 18.6.2.1 [bad.alloc]/p1 также не указывает кроме копии:
namespace std {
class bad_alloc : public exception {
public:
bad_alloc() noexcept;
bad_alloc(const bad_alloc&) noexcept;
bad_alloc& operator=(const bad_alloc&) noexcept;
virtual const char* what() const noexcept;
};
}
Кроме того, все типы исключений, определенные в стандартном наборе, не содержат членов-копий, явно или неявно. Для типов, определенных в <stdexcept>
, это обычно реализуется с помощью буфера с подсчетом ссылок для строки what()
. Это ясно указано в [исключение]/p2:
Каждый класс стандартной библиотеки T
, производный от класса exception, должен иметь общедоступный конструктор копирования и общедоступный оператор присваивания копирования, которые не завершаются с исключением. ...
То есть в качественной реализации (а для создания качественной реализации в этом плане не требуется геройства) мало того, что экземпляры-члены типов исключений не будут генерировать исключение (естественно потому, что они помечены noexcept
), они еще и не будут позвони terminate()
.
Для копирования стандартных типов исключений не существует режима отказа. Либо нет данных для копирования, либо данные подсчитываются и являются неизменяемыми.
person
Howard Hinnant
schedule
08.02.2014