返回非const左值引用

时间:2013-01-24 22:53:14

标签: c++ const

我正在尝试使用本书交互式计算机图形 - 自上而下的方法来学习计算机图形学,示例的代码是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

我只是评论它,因为它只是在调试应用程序时编译,但我想知道问题是什么以及如何解决它。

2 个答案:

答案 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)
    }