按值返回总是const吗?

时间:2012-11-14 19:09:25

标签: c++ return-value rvalue-reference temporary-objects pass-by-rvalue-reference

此代码无法编译:

class C {};

void foo (C& c) {}

C bar() { return C(); }

int main()              
{
  foo(bar());
}               

foo(bar())行中的编译错误(GCC 4.1.2):

  

“C&”类型的非const引用的无效初始化   来自临时的'C'

bar()返回一个mutable对象时,它应该编译...
为什么C ++不允许上面的代码?


编辑:我在an answer below总结了所有答案中的所有好主意; - )

8 个答案:

答案 0 :(得分:13)

此处适用的规则是您不能创建对临时对象的非const引用。如果foo被声明为foo(const C&),则代码就可以了。

但临时对象本身不是const;你可以在其上调用非const成员函数,例如bar().non_const_member_function()

使用C ++ 11,可以编写foo来获取右值引用;在这种情况下,电话会没问题:

void foo(C&&);
foo(bar());  // okay

答案 1 :(得分:8)

这是因为bar返回的值是临时值。因为它的存在是暂时的,所以你不能使用指针或引用它。

但是,如果您存储该临时的副本,就像在第二次更改中那样,您不再将对临时对象的引用传递给foo,而是引用一个真实的有形物体。在第一种情况下,当您更改为对常量对象的引用时,编译器会确保临时对象保持足够长的时间(根据C ++规范)。

答案 2 :(得分:3)

可修改(左值)引用不绑定到临时值。但是,const-references 执行绑定到临时值。它与value返回的对象是否为const无关;这只是表达是否是暂时的问题。

例如,以下 有效:

struct C { void i_am_non_const() {} };

int main()
{
    bar().i_am_non_const();
}

答案 3 :(得分:3)

问题不在于bar的宣言,而在于foo的宣言。 foo采用非const引用,临时数只能绑定到const引用(然后延长临时的生命周期以匹配它所绑定的引用的生命周期)。 / p>

允许非const引用绑定到临时引用没有多大意义。非const引用意味着它将修改绑定到它的任何对象。修改临时文件没有任何意义,因为它的生命周期是有限的,一旦超出范围,更改就会丢失。

答案 4 :(得分:1)

这是一个设计选择。这里没有什么本质上不可能的。只是一个设计选择。

在C ++ 11中,你有第三种选择,也是上级替代方案:

void foo(C && c) {} 

即,使用rvalue-references。

答案 5 :(得分:1)

它不是const,但它是一个临时的 rvalue 。因此,它无法绑定到非const 左值引用。

它可以绑定到const或 rvalue 引用,您可以在其上调用成员函数(const或不):

class C { void f(); };

void foo_const(C const &);
void foo_rvalue(C &&);

foo_const( bar() );  // OK
foo_rvalue( bar() ); // OK
bar().f();           // OK

答案 6 :(得分:0)

真实的,事实是,获得对临时值的引用是没有意义的。

通过引用传递对象的重点是它允许您修改其状态。但是,对于临时的情况,就其本质而言,能够修改它并不是特别有用,因为您无法在代码中再次获取它以查看更改。

但是,如果您有const引用,则会有所不同。由于您只阅读const参考文献,因此能够在那里使用临时工具是完全合理的。这就是为什么编译器会" hack"围绕它,为你提供一个更永久的地址,你想要转向"转向"进入const引用。

因此,规则是您无法获得对临时值的非const引用。 (这在C ++ 11中略有改变,我们有一种新类型的引用可以满足这个目的,但是方法应该以特殊的方式处理它们。)

答案 7 :(得分:0)

谢谢大家的回答:-)
在这里,我收集你的好主意; - )

答案

按值返回 const。例如,我们可以调用按值返回的非const成员函数

class C { 
  public:
    int x;
    void set (int n) { x = n; }  // non-const function
};

C bar()  { return C(); }

int main ()
{
    bar.set(5); // OK
}

C ++不允许对常量对象进行非常量引用
但是,C ++ 11允许非const rvalue-references 到临时对象。 ; - )

说明

class C {};

void foo (C& c) {}

C bar()  { return C(); }
//bar() returns a temporary object
//temporary objects cannot be non-const referenced

int main()
{
  //foo() wants a mutable reference (i.e. non-const)
  foo( bar() ); // => compilation error     
}                 

三个修复

  1. 更改foo声明

      void foo (const C& c) {}
    
  2. 使用其他对象

      int main()              
      {
        C c;
        foo( c = bar() );
      }
    
  3. 使用C ++ 11 rvalue-reference

      void foo(C && c) {}
    
  4. 而且

    要确认临时对象是const,上述源代码失败的原因相同:

    class C {};
    
    void foo(C& c) {}
    
    int main()                
    {
      foo( C() );
    }