厳密に言えば、エラーの正式な理由は非定数参照を一時オブジェクトにバインドしようとすることですが、ここでの本当の問題は、参照、つまり一時オブジェクトへの参照を返そうとすることです。参照がconstであるかどうかは関係ありません。
一時オブジェクトは、returnステートメントが完了した直後に破棄され、破棄されたオブジェクトにバインドされたぶら下がっている参照が返されます。つまり、returntypeをconstreferenceに変更してこのコードを「修正」しようとしても、正しく機能しません。
さらに、設計上、この関数は非定数参照を返すことになっているようです。つまり、この関数の戻り型を変更することはオプションではありません。非定数参照は、複合代入演算子が通常返すものです。「ゼロ除算」の状況の場合、デバッグブランチは早期に終了する(そしてもちろん、コードをコンパイルするためだけに何かを返す)ことになっています。
これを実現する1つの方法は、タイプのスタンドアロンオブジェクトを(たとえばmat2
、クラスの静的メンバーとして)宣言し、そのオブジェクトへの参照を返すことです。mat2
つまり、宣言します
class mat2 {
...
#ifdef DEBUG
static mat2 bad_result;
#endif // DEBUG
};
それを定義する
#ifdef DEBUG
mat2 mat2::bad_result;
#endif // DEBUG
そしてします
return bad_result;
エラーが検出されたときはいつでも。
return
あるいは(そしてはるかに簡単に)、そのステートメントの直前にローカルで宣言することができます
#ifdef DEBUG
if ( std::fabs(s) < DivideByZeroTolerance ) {
std::cerr << "[" << __FILE__ << ":" << __LINE__ << "] "
<< "Division by zero" << std::endl;
static mat2 bad_result;
return bad_result;
}
#endif // DEBUG
もちろん、この設計には明らかな欠陥があります。これは、外部コードが返されたオブジェクトを変更できるため、望ましくありません。ただし、エラーメッセージが出力されると、プログラムの動作は保証されないという考えが考えられますstd::err
。つまり、この場合、戻り値の変更可能性は問題になりません。
その最後の点を考慮に入れると、非静的ローカル変数を戻り値として使用することもできます
#ifdef DEBUG
if ( std::fabs(s) < DivideByZeroTolerance ) {
std::cerr << "[" << __FILE__ << ":" << __LINE__ << "] "
<< "Division by zero" << std::endl;
mat2 bad_result;
return bad_result;
}
#endif // DEBUG
ローカル変数への参照を返すことは、一時的なものへの参照を返すことと同じくらい間違っています(ほぼ同じ理由で)。ただし、「エラー後の保証なし」アプローチでは、「機能」します。つまり、エラーメッセージが修正されます。