Все GCC 4.8.4, 4.9.3, 5.3.0 проходят тесты для std::exception
(для любого из опций -std = С++ 11/1y/14/1z/17, если доступно):
static_assert(std::is_nothrow_copy_constructible<std::exception>::value, "test exception");
static_assert(std::is_nothrow_copy_assignable <std::exception>::value, "test exception");
Хорошо, поскольку std::exception
не имеет особых элементов (С++ 14 18.8.1):
namespace std { class exception { public: exception() noexcept; exception(const exception&) noexcept; exception& operator=(const exception&) noexcept; virtual ~exception(); virtual const char* what() const noexcept; }; }
К сожалению, все вышеперечисленные компиляторы терпят неудачу при следующих static_assert
s:
static_assert(std::is_nothrow_copy_constructible<std::runtime_error>::value, "test runtime_error");
static_assert(std::is_nothrow_copy_assignable <std::runtime_error>::value, "test runtime_error");
Стандарт содержит только следующее о std::runtime_error
в 19.2.6:
namespace std { class runtime_error : public exception { public: explicit runtime_error(const string& what_arg); explicit runtime_error(const char* what_arg); }; }
Но ничего не говорится об noexcept
других (неявно объявленных специальных) членах и требованиях к реализации хранилища what_arg
.
В стандарте (С++ 14) сказано следующее в 15.4/14:
Наследующий конструктор (12.9) и неявно объявленный специальный Функция члена (раздел 12) имеет спецификацию исключения. Если f наследующий конструктор или неявно объявленный дефолт конструктор, конструктор копирования, конструктор перемещения, деструктор, копия оператор присваивания или оператор переадресации, его неявный exception-specification указывает тип-идентификатор T тогда и только тогда, когда T разрешено спецификацией исключения функции, вызываемой напрямую по неявному определению fs; f разрешает все исключения, если какая-либо функция напрямую вызывает все исключения, а f имеет спецификация исключения noexcept (true), если каждая функция напрямую invokes не допускает исключений.
И следующее в 18.8.1/2:
Каждый стандартный класс библиотеки T, который проистекает из исключения класса, должен иметь общедоступный конструктор копий и публично доступный оператор назначения копирования, который не выходит с исключение.
Так как std::runtime_error
не раскрывает реализацию хранилища what_arg
, мы не знаем, являются ли это (специальные) члены неэксклюзивными или нет, поэтому невозможность создания конструктора копирования std::runtime_error
или экземпляра копирования не разрешима. Наша единственная ставка - 18.8.1 выше.
Вопрос 1/a) Мы рассматриваем конструктор копирования std::runtime_error
или присваивание копии как noexcept (1, 2). Это настоящая/современная/лучшая практика?
Вопрос 1/b) Нам не нужно явно указывать это в стандарте? (Как в 18.8.2, Class bad_exception
)
Вопрос 1/c) Является ли это ошибкой в GCC, что он не прошел тесты static_assert выше?
Вопрос 2) Если вышеуказанный вывод неверен, может ли кто-нибудь указать мне раздел (разделы) в стандарте, в котором указано, что std:: runtime_error имеет noexcept конструктор копирования (и назначение копии)? (Или там, где указано, что они не являются.)