我正在尝试使用本书交互式计算机图形 - 自上而下的方法来学习计算机图形学,示例的代码是in this link
有一个名为'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
我只是评论它,因为它只是在调试应用程序时编译,但我想知道问题是什么以及如何解决它。
答案 0 :(得分:6)
严格地说,虽然错误的正式原因是尝试将非const 引用绑定到临时,但真正的问题是尝试返回引用< / em>,对临时对象的任何引用。引用是否为常量并不重要。
临时对象将在return语句完成后立即销毁,从而导致绑定引用绑定到正在返回的现在销毁的对象。换句话说,即使我们尝试通过将返回类型更改为const引用来“修复”此代码,它仍然无法正常工作。
此外,似乎设计此函数假定返回非const引用,这意味着更改此函数的返回类型不是一个选项。非const引用是复合赋值运算符通常返回的内容。调试分支应该提前终止(当然,在“除零”的情况下,返回一些东西,只是为了使代码编译)。
实现这一目标的一种方法是声明类型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
返回对局部变量的引用与返回对临时变量的引用一样错误(原因大致相同)。但是,在“错误后无保证”方法中,它将“正常”,这意味着它将修复错误消息。
答案 1 :(得分:3)
问题是非const
左值引用无法绑定到临时值,即 rvalue 。只有const
左值引用(在C ++ 98和C ++ 11中)或右值引用(仅在C ++ 11中)可以。此运算符尝试返回对从函数返回时创建的临时值的左值引用:
mat2& operator /= ( const GLfloat s ) {
// ^^^^^
// RETURNS A NON-CONST LVALUE REFERENCE
...
return mat2(); // <--- CREATES A TEMPORARY (RVALUE)
}