C++ 返回非常量左值引用

C++ 返回非常量左值引用,c++,constants,C++,Constants,我正在尝试使用《交互式计算机图形学-自上而下的方法》一书学习计算机图形学,示例代码如下 有一个名为“mat.h”的头库,它提供了一些矩阵实用程序,但当我尝试使用Xcode编译时,会抛出以下错误: 对“Angel::mat2”类型的非常量左值引用无法绑定到“Angel::mat2”类型的临时引用。 引发该错误的代码段是: mat2& operator /= ( const GLfloat s ) { #ifdef DEBUG if ( std::fabs(s) < Divid

我正在尝试使用《交互式计算机图形学-自上而下的方法》一书学习计算机图形学,示例代码如下

有一个名为“mat.h”的头库,它提供了一些矩阵实用程序,但当我尝试使用Xcode编译时,会抛出以下错误:

对“Angel::mat2”类型的非常量左值引用无法绑定到“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
mat2&运算符/=(常量gls){
#ifdef调试
if(标准::晶圆厂<除零公差){

std::cerr问题在于非
常量
左值引用无法绑定到临时值,该临时值是右值。只有
常量
左值引用(在C++98和C++11中)或右值引用(仅在C++11中)可以绑定。此运算符试图将左值引用返回到从函数返回时创建的临时值:

    mat2& operator /= ( const GLfloat s ) {
//  ^^^^^
//  RETURNS A NON-CONST LVALUE REFERENCE
        ...
        return mat2(); // <--- CREATES A TEMPORARY (RVALUE)
    }
mat2&运算符/=(常量gls){
//  ^^^^^
//返回一个非常量左值引用
...

return mat2();//问题在于非
常量
左值引用无法绑定到临时的右值。只有
常量
左值引用(在C++98和C++11中)或右值引用(仅在C++11中)can。此运算符试图返回从函数返回时创建的临时变量的左值引用:

    mat2& operator /= ( const GLfloat s ) {
//  ^^^^^
//  RETURNS A NON-CONST LVALUE REFERENCE
        ...
        return mat2(); // <--- CREATES A TEMPORARY (RVALUE)
    }
mat2&运算符/=(常量gls){
//  ^^^^^
//返回一个非常量左值引用
...

return mat2();//严格来说,错误的正式原因是试图将非常量引用绑定到临时对象,但真正的问题是试图返回引用,即对临时对象的任何引用。引用是否为常量并不重要

在return语句完成后,临时对象将立即被销毁,导致绑定到当前已销毁对象的悬空引用被返回。换句话说,即使我们试图通过将返回类型更改为const reference来“修复”此代码,它仍然无法正常工作

此外,通过设计,似乎该函数应该返回一个非常量引用,这意味着更改该函数的返回类型不是一个选项。非常量引用是复合赋值运算符通常返回的内容。调试分支应该提前终止(当然,要返回一些东西,只要让代码编译就行)以防出现“被零除”的情况

实现这一点的一种方法是声明一个类型为
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

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

严格来说,错误的正式原因是试图将非常量引用绑定到临时对象,但真正的问题是试图返回引用,即对临时对象的任何引用。引用是否为常量并不重要

在return语句完成后,临时对象将立即被销毁,导致绑定到当前已销毁对象的悬空引用被返回。换句话说,即使我们试图通过将返回类型更改为const reference来“修复”此代码,它仍然无法正常工作

此外,通过设计,似乎该函数应该返回一个非常量引用,这意味着更改该函数的返回类型不是一个选项。非常量引用是复合赋值运算符通常返回的内容。调试分支应该提前终止(当然,要返回一些东西,只要让代码编译就行)以防出现“被零除”的情况

实现这一点的一种方法是声明一个类型为
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

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

这是一种奇怪的处理方式…这是一种奇怪的处理方式…好了,现在我知道问题出在哪里了。如果我使用上一个解决方案,所有内容都会编译并运行,但有一条警告说“引用与局部变量“bad_result”关联的堆栈内存返回了什么?”什么意思?@BRabbit27:这意味着一旦函数返回,变量将被销毁。因此,返回的引用将绑定到“nothing”。在此搜索“return reference local variable”有很多解释。好的,现在我知道问题出在哪里了。如果我使用上一个建议的解决方案,所有的东西都会编译并运行,但是有一个警告说“引用与局部变量“bad_result”相关的堆栈内存返回了”,这意味着什么?@BRabbit27:这意味着一旦函数返回,变量就会被销毁。a因此,返回的引用将被绑定到“nothing”。在这里搜索“return reference local variable”以获得众多解释。