Ответ 1
В соответствии со ссылкой cpp на выбрасываемое выражение:
Во-первых, copy-инициализирует объект исключения из выражения (это может вызвать конструктор перемещения для выражения rvalue, а для копирования/перемещения может быть выполнено исключение копирования)
Таким образом, ваш код, если он в порядке, но будет вызван конструктор копирования, что может быть нежелательно с точки зрения эффективности. Тем не менее, исключение копирования может произойти, если (выделено мной)
При следующих обстоятельствах компиляторам разрешено, но не требуется опускать копию
[omissis]
В выражении throw, когда операндом является имя энергонезависимого объекта с автоматической продолжительностью хранения, который не является параметром функции или параметром предложения catch, и область действия которого не выходит за пределы самой внутренней попытки. блок (если есть триб-блок).
В качестве примера рассмотрим следующий код
#include <exception>
#include <iostream>
struct something_bad_happened_exception : std::exception {
something_bad_happened_exception(const something_bad_happened_exception& r) {
std::cout << "A copy has occoured!" << std::endl;
}
something_bad_happened_exception() { }
};
int main()
{
std::cout << "First throw" << std::endl;
try {
const something_bad_happened_exception e;
throw e;
}
catch (const std::exception& ex)
{
std::cout << "Caught exception" << std::endl;
}
std::cout << "Second throw" << std::endl;
try {
throw something_bad_happened_exception();
}
catch (const std::exception& ex)
{
std::cout << "Caught exception" << std::endl;
}
return 0;
}
Скомпилируя код с помощью gcc 8.2.1
и clang 6.0
, с опцией -O3
, вы получите
First throw
A copy has occoured!
Caught exception
Second throw
Caught exception
Первый throw
соответствует вашему примеру. Даже если копия e
может быть опущена, ни gcc
, ни clang
не реализуют исключение копирования.
Второй throw
имеет временный анонимный доступ, и копия не появляется.