1

我正在尝试使用交互式计算机图形学 - 自上而下的方法这本书来学习计算机图形学,示例代码在此链接中

有一个名为“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

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

4

2 回答 2

6

严格来说,虽然错误的正式原因是尝试将非常量引用绑定到临时对象,但这里真正的问题是尝试返回引用,即对临时对象的任何引用。引用是否为 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

返回对局部变量的引用与返回对临时变量的引用一样错误(原因大致相同)。但是,在“出错后不保证”的方法中,它将“起作用”,这意味着它将修复错误消息。

于 2013-01-24T23:16:04.303 回答
3

问题是非const左值引用不能绑定到临时值,即右值。只有const左值引用(在 C++98 和 C++11 中)或右值引用(仅在 C++11 中)可以。此运算符试图返回一个左值引用,该引用指向从函数返回时创建的临时对象:

    mat2& operator /= ( const GLfloat s ) {
//  ^^^^^
//  RETURNS A NON-CONST LVALUE REFERENCE
        ...
        return mat2(); // <--- CREATES A TEMPORARY (RVALUE)
    }
于 2013-01-24T22:55:38.613 回答