无法将临时对象作为引用传递
Can't pass temporary object as reference
这是一个非常小的例子:
class Foo
{
public:
Foo(int x) {};
};
void ProcessFoo(Foo& foo)
{
}
int main()
{
ProcessFoo(Foo(42));
return 0;
}
上面的内容在Visual Studio上编译得很好,但在Linux和Mac上会生成错误。
编译上述内容会生成以下内容:
$ g++ -std=c++11 -c newfile.cpp
newfile.cpp: In function ‘int main()’:
newfile.cpp:23:23: error: invalid initialization of non-const reference of type ‘Foo&’ from an rvalue of type ‘Foo’
ProcessFoo(Foo(42));
^
newfile.cpp:14:6: note: in passing argument 1 of ‘void ProcessFoo(Foo&)’
void ProcessFoo(Foo& foo)
我找到了三种解决方法:
- 为调用 ProcessFoo 创建一个临时变量。
喜欢这个:
Foo foo42(42);
ProcessFoo(foo42);
ProcessFoo采用常量引用:
void ProcessFoo(const Foo& foo)
ProcessFoo只是让Foo按值传递。
void ProcessFoo(Foo foo)
为什么编译器禁止我的原始代码?(它防范什么(? 上述三种解决方法中的每一个都满足编译器的要求是什么? MSVC允许什么,但g++不允许?
根据设计,C++只允许将临时传递给 const 引用、值或右值引用。 这个想法是,采用非 const 引用参数的函数声明它想要修改参数并允许它返回到调用方。 临时这样做毫无意义,很可能是一个错误。
而且我不知道你运行的是什么版本的 g++。 它在这里不起作用:http://coliru.stacked-crooked.com/a/43096cb398cbc973
为什么编译器禁止我的原始代码?
因为这是标准所禁止的:
8.5.3 参考文献 5
...
否则,引用应是非易失性常量类型的左值引用(即 cv1 应为 康斯特(,或引用应为右值引用。
[ 示例:
双倍&RD2 = 2.0;错误:不是左值,引用不是常量
...
'
它防范什么?
无意中修改了将在函数调用后销毁的对象。
上述三种解决方法中的每一个都满足编译器的要求是什么?
1
创建命名对象并3
副本。
2
之所以有效,是因为可以简单地延长对象的生存期,同时防止对其进行更改。
MSVC允许什么,但g++不允许?
因为它是一种语言扩展。通过转到Property Pages->C/C++->Language->Disable Language Extensions
禁用它,您将收到错误。
为什么编译器禁止我的原始代码?
MSVC 有一个扩展,允许临时绑定到非常量左值引用。当然,这不是符合标准的功能,所以我会远离它以方便移植。例如,它不适用于您所看到的最新版本的 GCC 和 Clang。
上述三种解决方法中的每一个都满足编译器的要求是什么?
早在 C++03 年,表达式只能是左值或右值。引用只能指定对象的"左值",因此使用它的目的是为预先存在的对象着色。相比之下,右值在它们出现的表达式之外不存在。此外,引用的最终结果通常是复制或修改对象,并且像55
这样的修改右值对语言没有多大意义。
这些规则允许您将右值绑定到常量值的左值引用,在这种情况下,临时的生存期将延长到引用的生存期。当您按值获取对象时,将复制该对象。
对于 C++11,我们有右值引用和 x值,它们是为了交换所有权而制作的。这样一来,左值引用对 const 的用处就会降低。此外,如果按值是右值,则按值会导致移动。
一旦你声明了ProcessFoo的原型
void ProcessFoo(Foo& foo)
您正在传达您的意图,因为形式参数"foo"可能会被修改,因为它不是由 const & 传递的。
在呼叫现场,
ProcessFoo(Foo(42));
Foo(42( 正在创建一个不可修改的临时堆栈对象。可以按值传递或按引用传递到常量方法。
正如您自己列出的那样,满足这些约束会使编译器满意。
- 为您提供一个不是编译器生成的对象,并且由您控制。
- 通知编译器该方法保证对象的恒定性。
- 通知编译器此(临时(对象是按值传递的,因此没有问题。
- 为什么当我们有常量引用时创建临时对象?
- 返回对临时对象的引用
- 通过引用传递临时对象
- 存储对(可能)临时对象的引用是否合法,只要引用不比对象存活?
- 对临时对象的Const引用不会延长其生存期
- 为什么引用类型在使用临时对象访问时是左值
- 取消引用临时对象上的运算符
- 常量引用函数参数:是否可以禁止临时对象?
- 为什么临时对象可以绑定到常量引用?
- 为什么常量引用不能延长通过函数传递的临时对象的生存期?
- 使用常量引用延长临时对象的寿命
- 从函数返回引用是否会导致在使用'auto'时创建新的临时对象?
- 关于将临时对象传递给常量引用
- 将临时对象绑定到常量引用
- C++17:是编译器为(静态存储持续时间)const引用绑定创建的可修改的临时对象(和存储)
- 返回对本地临时对象 C++ 的引用
- 模板类型推导警告返回对本地临时对象的引用
- 为什么不对临时对象进行非常量引用
- 为什么我们可以非常量引用临时对象并延长其生命周期
- C++悬空的常量引用临时对象