此代码无法编译:
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总结了所有答案中的所有好主意; - )
答案 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
}
更改foo
声明
void foo (const C& c) {}
使用其他对象
int main()
{
C c;
foo( c = bar() );
}
使用C ++ 11 rvalue-reference
void foo(C && c) {}
要确认临时对象是const,上述源代码失败的原因相同:
class C {};
void foo(C& c) {}
int main()
{
foo( C() );
}