严格来说,虽然错误的正式原因是尝试将非常量引用绑定到临时对象,但这里真正的问题是尝试返回引用,即对临时对象的任何引用。引用是否为 const 无关紧要。
临时对象将在 return 语句完成后立即销毁,从而返回绑定到现在已销毁对象的悬空引用。换句话说,即使我们试图通过将返回类型更改为 const 引用来“修复”这段代码,它仍然无法正常工作。
此外,根据设计,该函数似乎应该返回一个非常量引用,这意味着更改该函数的返回类型不是一种选择。非常量引用是复合赋值运算符通常返回的内容。在“除以零”的情况下,调试分支应该提前终止(当然,返回一些东西,只是为了使代码编译)。
实现这一点的一种方法是声明一个独立的类型对象mat2
(例如,作为 class 的静态成员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
返回对局部变量的引用与返回对临时变量的引用一样错误(原因大致相同)。但是,在“出错后不保证”的方法中,它将“起作用”,这意味着它将修复错误消息。