Ответ 1
Ответ:
Да, вы все равно не хотите вставлять std::string
в свои типы исключений. Исключения часто копируются, иногда без вашего ведома. Например, на некоторых платформах std::rethrow_exception
будет копировать исключение (а на некоторых - нет).
Для лучшей практики сохраните свой конструктор копирования noexcept
.
Однако все не потеряно. Малоизвестный факт заключается в том, что в С++ всегда существовал стандарт стандартного неизменяемого типа строк с подсчетом (с конструктором без метаданных), просто с запутанным именем. На самом деле два имени:
logic_error
runtime_error
Спецификации для этих типов таковы, что они должны содержать неизменяемый объект, подобный объекту с подсчетом. Ну, не совсем непреложный. Вы можете заменить строку назначением. Но вы не можете изменить строку на месте.
Мой совет заключается в том, чтобы либо получить один из этих типов, либо, если это неприемлемо, вставить один из этих типов и рассматривать его как неизменяемый тип строки, подсчитанный счетчиком:
#include <stdexcept>
#include <iostream>
class error1
: public std::runtime_error
{
using msg_ = std::runtime_error;
public:
explicit error1(std::string const& msg)
: msg_(msg)
{}
};
class error2
{
std::runtime_error msg_;
public:
explicit error2(std::string const& msg)
: msg_(msg)
{}
char const* what() const noexcept {return msg_.what();}
};
void
test_error1()
{
try
{
throw error1("test1");
}
catch (error1 const& e)
{
std::cout << e.what() << '\n';
}
}
void
test_error2()
{
try
{
throw error2("test2");
}
catch (error2 const& e)
{
std::cout << e.what() << '\n';
}
}
int
main()
{
test_error1();
test_error2();
}
std:: lib позаботится обо всем управлении строкой и управлении памятью для вас, и вы получите noexcept
копирование в сделке:
static_assert(std::is_nothrow_copy_constructible<error1>{}, "");
static_assert(std::is_nothrow_copy_assignable <error1>{}, "");
static_assert(std::is_nothrow_copy_constructible<error2>{}, "");
static_assert(std::is_nothrow_copy_assignable <error2>{}, "");