RVO对对象成员起作用吗?
Does RVO work on object members?
考虑以下内容:
struct A { /* ... */ };
A foo() {
auto p = std::make_pair(A{}, 2);
// ... do something
return p.first;
}
auto a = foo();
p.first
会被复制、移动或RVO-ed吗?
我发现在Visual Studio 2010和gcc-5.1中RVO是而不是应用(参见例如http://coliru.stacked-crooked.com/a/17666dd9e532da76)。
标准的相关章节为12.8.31.1 [class.copy]。它声明允许复制省略(我的高亮显示):
在具有类返回类型的函数的返回语句中,当表达式是与函数返回类型相同的非易失性自动对象的名称(函数参数或由处理程序([exception .handle])的异常声明引入的变量除外)(忽略cv-限定)时,可以通过将自动对象直接构造为函数的返回值
来省略复制/移动操作。
由于p.first
不是对象的名称,因此禁止使用RVO
只是添加一点燃料,如果RVO在发挥作用,该函数将如何?调用者将A
的实例放在内存中的某个地方,然后调用foo
对其进行赋值(更好的是,让我们假设A
是一个更大结构的一部分,并且让我们假设它是正确对齐的,这样结构的下一个成员就在A
的实例之后)。假设RVO在起作用,p
的first
部分位于调用者想要的位置,但是int
是second
的位置在哪里?它必须位于A
实例的后面,以保持pair
正常工作,但是在源位置,A
实例的后面还有其他成员。
我希望RVO不会在这里发生,因为您只是返回一个较大对象的一部分。当first
必须处于可破坏状态时,可能会发生移动
@atkins第一个找到了答案。只是添加这个小测试程序,你可能会发现在未来跟踪移动/分配行为时有用。
#include <iostream>
#include <string>
using namespace std::string_literals;
struct A {
A()
: history("created")
{
}
A(A&& r)
: history("move-constructed,"s + r.history)
{
r.history = "zombie: was "s + r.history;
}
A(const A& r)
: history("copied from: " + r.history)
{
}
~A() {
history = "destroyed,"s + history;
std::cout << history << std::endl;
}
A& operator=(A&& r) {
history = "move-assigned from " + r.history + " (was "s + history + ")"s;
r.history = "zombie: was "s + r.history;
return *this;
}
A& operator=(const A&r ) {
history = "copied from " + r.history;
return *this;
}
std::string history;
};
A foo() {
auto p = std::make_pair(A{}, 2);
// ... do something
return p.first;
}
auto main() -> int
{
auto a = foo();
return 0;
}
示例输出:
destroyed,zombie: was created
destroyed,move-constructed,created
destroyed,copied from: move-constructed,created
考虑以下代码:
struct A {};
struct B {};
struct C { B c[100000]; };
A callee()
{
struct S
{
A a;
C c;
} s;
return s.a;
}
void caller()
{
A a = callee();
// here should lie free unused spacer of size B[100000]
B b;
}
"部分"RVO应该导致调用方堆栈使用过度膨胀,因为(我认为)S
只能完全在调用方堆栈帧中构造。
~S()
的行为:
// a.hpp
struct A {};
struct B {};
struct C { A a; B b; ~C(); };
// a.cpp
#include "a.hpp"
~C() { /* ... */; }
// main.cpp
#include "a.hpp"
A callee()
{
C c;
return c.a;
} // How to destruct c partially, having the user defined ~C() in another TU?
// Even if destructor is inline and its body is visible,
// how to automatically change its logic properly?
// It is impossible in general case.
void caller() { A a = callee(); }
相关文章:
- 为什么 operator() 处的指针成员不起作用?
- 在 C++ 中通过引用传递类成员时,Const 不起作用
- 静态数据成员:它"const declaration / constexpr definition"起作用?
- 为什么以下成员初始值设定项在c++中不起作用
- 为什么视频捕获在成员函数中不起作用?
- 为什么static_assert在带有 const 参数的成员函数中不起作用?
- 为什么 SFINAE 在这个简单的成员函数重载中不起作用
- 尝试调用成员函数指针不起作用
- SFINAE:检测成员变量的存在在 g++ 上不起作用
- 在文档中引用使用doxygen的结构成员不起作用;结构成员未出现在文档中
- 模板化类的成员函数的规范化不起作用
- C++中的友元成员函数 - 转发声明不起作用
- 绑定数据成员在VS2012中不起作用
- 优先级队列成员函数不起作用
- C++迭代时删除列表成员:标准解决方案不起作用
- 如果我在静态成员中使用,Qt tr() 不起作用
- 不同类的成员列表实现不起作用
- 为什么调用成员函数就好像它是静态的(当它不是静态时)在C++中起作用?
- RVO对对象成员起作用吗?
- Lambda作为类成员起作用