我正在尝试使用书籍学习计算机图形学交互式计算机图形 - 自上而下的方法,示例的代码就在这个链接中
有一个名为'mat.h'的头库提供了一些矩阵实用程序,但是当我尝试使用Xcode编译时,会抛出以下错误:
对类型'Angel :: mat2'的非const左值引用不能绑定到'Angel :: mat2'类型的临时值
抛出该错误的代码段是:
mat2& operator /= ( const GLfloat s ) {
#ifdef DEBUG
if ( std::fabs(s) < DivideByZeroTolerance ) {
std::cerr << "[" << __FILE__ << ":" << __LINE__ << "] "
<< "Division by zero" << std::endl;
return mat2();
}
#endif // DEBUG
Run Code Online (Sandbox Code Playgroud)
我只是评论它,因为它只是在调试应用程序时编译,但我想知道问题是什么以及如何解决它.
严格来说,虽然错误的正式原因是尝试将非const引用绑定到临时,但这里真正的问题是尝试返回引用,对临时对象的任何引用.引用是否为const无关紧要.
在return语句完成后,临时对象将被销毁,从而导致绑定到正在被返回的现在被破坏的对象的悬挂引用.换句话说,即使我们尝试通过将返回类型更改为const引用来"修复"此代码,它仍然无法正常工作.
而且,看起来设计这个函数应该返回一个非const引用,这意味着改变这个函数的返回类型不是一个选项.非const引用是复合赋值运算符通常返回的内容.调试分支应该提前终止(当然,在"除零"的情况下,返回一些东西,只是为了使代码编译).
实现这一点的一种方法是声明一个类型的独立对象mat2(例如,作为类的静态成员mat2)并返回对它的引用.即宣布
class mat2 {
...
#ifdef DEBUG
static mat2 bad_result;
#endif // DEBUG
};
Run Code Online (Sandbox Code Playgroud)
定义它
#ifdef DEBUG
mat2 mat2::bad_result;
#endif // DEBUG
Run Code Online (Sandbox Code Playgroud)
然后呢
return bad_result;
Run Code Online (Sandbox Code Playgroud)
每当检测到错误时.
或者(更容易)您可以在该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
Run Code Online (Sandbox Code Playgroud)
当然,这种设计存在明显的缺陷,因为外部代码将能够修改返回的对象,这是不可取的.但是,最有可能的想法是,一旦打印出错误消息,程序的行为就不能得到保证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
Run Code Online (Sandbox Code Playgroud)
返回对局部变量的引用与返回对临时变量的引用一样错误(原因大致相同).但是,在"错误后无保证"方法中,它将"工作",这意味着它将修复错误消息.