エラー処理は、C++ コンストラクターでの課題です。いくつかの一般的なアプローチがありますが、そのすべてに明らかな欠点があります。たとえば、例外をスローすると、コンストラクターの早い段階で割り当てられたリソースのリークが発生する可能性があり、エラーが発生しやすいアプローチになります。静的init()
メソッドを使用することも一般的な解決策ですが、RAII の原則に反します。
このテーマを研究していると、この回答とブログで という名前の C++17 機能の使用を提案していることがstd::optional<>
わかり、有望であることがわかりました。ただし、この種のソリューションには根本的な問題があるようです。ユーザーがオブジェクトを取得すると、デストラクタが即座にトリガーされます。
問題を説明する簡単なコード例を次に示します。私のコードは上記のソースに基づいています
class A
{
public:
A(int myNum);
~A();
static std::optional<A> make(int myNum);
bool isBuf() { return _buf; };
private:
char* _buf;
};
std::optional<A> A::make(int myNum)
{
std::cout << "A::make()\n";
if (myNum < 8)
return {};
return A(myNum);
}
A::A(int myNum)
{
std::cout << "A()\n";
_buf = new char[myNum];
}
A::~A()
{
std::cout << "~A()\n";
delete[]_buf;
}
int main()
{
if (std::optional<A> a = A::make(42))
{
if (a->isBuf())
std::cout << "OK\n";
else
std::cout << "NOT OK\n";
std::cout << "if() finished\n";
}
std::cout << "main finished\n";
}
このプログラムの出力は次のようになります。
A::make()
A()
~A()
OK
if() finished
~A()
その後、2 回削除しようとしたため、(少なくとも Visual C++ 環境では) 実行時エラーが発生しましたa->_buf
。
cout
この問題が非常に複雑なコードをデバッグしていることがわかったので、読者の便宜のために使用しましたが、問題は明らかです - のreturn
ステートメントA::make()
はオブジェクトを構築しますが、それはA::make()
スコープの終わりであるため、デストラクタが呼び出されます。ユーザーは、オブジェクトが初期化されていることを確認します (どのようにメッセージが表示されたかに注意して"OK"
ください)。実際には、オブジェクトは破棄されています。if()
main
a->~A()
それで、私はこれを間違っていますか?コンストラクターでの for エラー処理の使用std::optional
は一般的です。前もって感謝します