c++ 11本地命名引用返回值(xvalue)
C++11 local named references to return value (xvalue)?
我们有以下类型X
和函数f
:
struct X { ... };
X f() { ... };
现在考虑另一个函数g
的三个可选定义:
(1)
void g()
{
X x = f();
...
}
(2)
void g()
{
X& x = f();
...
}
(3)
void g()
{
X&& x = f();
...
}
在三种不同的情况下,定义行为(或潜在行为)的区别是什么?(假设占位符"……"三种情况下的代码是相同的)
更新:
如果g
返回一个X
:下面是合法的和正确的吗?
X g()
{
X&& x = f();
...
return move(x);
}
(移动是必要的,它做什么吗?)
您是否期望RVO链,以便下面的代码产生相同的代码?
X g()
{
X x = f();
...
return x;
}
2是非法的。其他两个基本相同——x
是X
类型的可变左值,其生命周期在g()
返回时结束。
当然,严格地说,第一种调用move构造函数(但它是一些RVO/NRVO操作的主要候选),而第三种不调用,所以如果X是不可移动的(非常奇怪……),第三种情况是合法的,但第一种情况不是,并且第一种情况可能更昂贵。然而,编译器选项和不可移动类型的实际情况是,这几乎完全是一个技术问题,如果您能实际演示任何这样的情况,我会感到惊讶。
表达式f()
按值返回,所以它是prvalue。
-
创建一个类型为
X
的新对象,初始化为表达式f()
,这是一个类型为X
的右值。如何构造新的X
对象取决于它是否有move构造函数。如果它有一个移动构造函数(或一个接受X
右值的模板构造函数),它将被调用,否则如果它有一个复制构造函数,它将被调用。实际上,编译器几乎肯定会忽略构造函数调用,但是适当的构造函数必须是可访问的,并且不能被删除。 -
这甚至没有编译,你在发布之前没有尝试过,你会得到一个反对票!
-
这将创建一个类型为
X&&
的新引用,并通过将其绑定到f()
返回的右值来初始化它。 右值的生存期将延长到与引用
x
相同的生存期。行为上的区别可能没有什么,假设省略了move/copy,但是(1)和(3)之间在语义上有区别,因为一个对构造函数进行重载解析,这可能会失败,而另一个总是工作。
如果g返回一个X,下面的操作合法且正确吗?
这是合法的。move
是不必要的,有一个特殊的规则说,当按值返回一个局部变量时,构造函数查找首先完成,好像变量是一个右值,所以如果X
有一个移动构造函数,它将被使用,无论你是否使用move(x)
。RVO应该"连锁"。如果g
返回X&
,那么在这两种情况下都有问题,因为它绑定的对象将在g
结束时超出作用域。
始终限定std::move
以防止ADL是一种良好的做法。std::forward
也是如此。如果你想调用std::move
或std::forward
,那么要显式,不要依赖于范围内或可见的没有过载,move
和forward
不是像swap
那样的自定义点。
与其通过问关于SO的问题来学习c++,为什么不写代码来测试会发生什么并向自己证明呢?在g++中,您可以使用-fno-elide-constructors
标志来关闭构造函数省略,以查看没有省略时会发生什么,当不使用该标志(默认值)时,您可以轻松地为自己测试RVO是否"链"。
- 从python中调用C++函数并获取返回值
- 为什么模板类中的对象不能返回值
- 返回值优化:显式移动还是隐式
- lock_guard是否保护返回值
- 调用CreateProcess()并获取字符串的返回值
- 如何使 windows 命令提示符在C++可执行文件上显示返回值?
- 编译器警告:执行到达值返回函数的末尾而不返回值
- 查找 GCD:并非所有控制路径都返回值
- 在 Arduino 上使用 sscanf 会导致与 const char * 不匹配,并且返回值始终相同,尽管输入值不同
- 将返回值存储在函数指针数组的指针中是如何工作的?
- 如何从 std::thread 返回值
- 将返回值从 exe 传递到 bat,并将其传递给 C# 中的进程
- 方法错误"not all control paths return a value"和方法不返回值
- 如何读取 C++ SAFEARRAY**,该 SAFEARRAY** 是 COM 互操作的结果,其中 C# 返回值为
- 对fread的返回值感到困惑
- 程序不向函数返回值
- 如何在另一个函数中使用返回值作为参数?
- 如何使用 uint64_t 键类型从 std::map<int, std::string> 返回值?
- 使用 std::p air 进行返回值优化
- c++ 11本地命名引用返回值(xvalue)