答えは次のとおりです。
std::string
はい、例外タイプに a を埋め込みたくありません。例外は、知らないうちにコピーされることがよくあります。たとえば、一部のプラットフォームでstd::rethrow_exception
は例外がコピーされます (一部のプラットフォームではコピーされません)。
ベスト プラクティスとして、コピー コンストラクターを保持してくださいnoexcept
。
しかし、すべてが失われるわけではありません。あまり知られていない事実として、C++ は常に不変の ref-counted 文字列型 (例外をスローしないコピー コンストラクターを使用) を標準内に持ち、難読化された名前だけを使用していました。実際には2つの名前:
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>{}, "");