Return局部栈变量成员值优化
Return value optimization of a member of a local stack variable
我有一段通用代码,当实例化时,归结为:
struct A{...};
A f1(){
A ret;
std::pair<A&, int> p(ret, 1);
p = g(); // g returns a pair<A, int>, but I am not interested in g
return ret; // RVO :)
};
据我了解,这将适用于 RVO。
问题是,这个其他代码 return 具有 RVO 的 A
类型的对象吗?
A f2(){
std::pair<A, int> p;
p = g();
return p.first; // RVO ?
};
我知道由于 return 对象被隐藏,它不会执行 RVO,或者编译器可能无法选择 "optimization"。
但我没有看到为什么它不可能的根本原因,换句话说,我认为为了一致性,它应该做 RVO(我想要)。
之所以问,是因为我觉得 f2
比 f1
更优雅。
最后一个版本应该做RVO吗?如果是这样,它是否依赖于编译器?
我对 gcc 8.1 的粗略测试表明 RVO 在下面的 f2
和 f3
中不起作用:
struct A{
double something;
A() = default;
A(A const& other) : something(other.something){std::cerr << "cc" << '\n';}
A(A&& other) : something(other.something){std::cerr << "mc" << '\n';}
};
A f1(){
A ret;
std::pair<A&, int> p(ret, 1);
p.first.something = 5.;
return ret; // RVO :)
};
A f2(){
std::pair<A, int> p;//(ret, 1);
p.first.something = 5.;
return p.first; // no RVO :(
};
A f3(){
std::pair<A, int> p;//(ret, 1);
p.first.something = 5.;
return std::move(p).first; // no RVO :(
};
int main(){
A a1 = f1(); // prints nothing, RVO
A a2 = f2(); // prints "cc"; no RVO! Why?
A a3 = f3(); // prints "mc" (no much gain in this case); still no RVO!
}
要使 RVO 工作,return 值需要在调用者希望找到它的存储中实例化。也许这是一个名称由调用约定指定的寄存器,或者它可能在堆栈上。
std::pair<A, int>
本质上是:
struct foo {
A first;
int second;
};
现在,如果 return 值需要与 sizeof(A)
存储在特定位置,但该对的大小较大,则不可能将其存储在那里。 RVO 仍然可以工作的唯一方法是如果被调用者知道 return 值后面的 sizeof(int)
字节在函数执行时被允许被破坏。但是在这种情况下,该语言可能不需要 RVO,因为它可能无法在每个调用约定中实现。
我有一段通用代码,当实例化时,归结为:
struct A{...};
A f1(){
A ret;
std::pair<A&, int> p(ret, 1);
p = g(); // g returns a pair<A, int>, but I am not interested in g
return ret; // RVO :)
};
据我了解,这将适用于 RVO。
问题是,这个其他代码 return 具有 RVO 的 A
类型的对象吗?
A f2(){
std::pair<A, int> p;
p = g();
return p.first; // RVO ?
};
我知道由于 return 对象被隐藏,它不会执行 RVO,或者编译器可能无法选择 "optimization"。 但我没有看到为什么它不可能的根本原因,换句话说,我认为为了一致性,它应该做 RVO(我想要)。
之所以问,是因为我觉得 f2
比 f1
更优雅。
最后一个版本应该做RVO吗?如果是这样,它是否依赖于编译器?
我对 gcc 8.1 的粗略测试表明 RVO 在下面的 f2
和 f3
中不起作用:
struct A{
double something;
A() = default;
A(A const& other) : something(other.something){std::cerr << "cc" << '\n';}
A(A&& other) : something(other.something){std::cerr << "mc" << '\n';}
};
A f1(){
A ret;
std::pair<A&, int> p(ret, 1);
p.first.something = 5.;
return ret; // RVO :)
};
A f2(){
std::pair<A, int> p;//(ret, 1);
p.first.something = 5.;
return p.first; // no RVO :(
};
A f3(){
std::pair<A, int> p;//(ret, 1);
p.first.something = 5.;
return std::move(p).first; // no RVO :(
};
int main(){
A a1 = f1(); // prints nothing, RVO
A a2 = f2(); // prints "cc"; no RVO! Why?
A a3 = f3(); // prints "mc" (no much gain in this case); still no RVO!
}
要使 RVO 工作,return 值需要在调用者希望找到它的存储中实例化。也许这是一个名称由调用约定指定的寄存器,或者它可能在堆栈上。
std::pair<A, int>
本质上是:
struct foo {
A first;
int second;
};
现在,如果 return 值需要与 sizeof(A)
存储在特定位置,但该对的大小较大,则不可能将其存储在那里。 RVO 仍然可以工作的唯一方法是如果被调用者知道 return 值后面的 sizeof(int)
字节在函数执行时被允许被破坏。但是在这种情况下,该语言可能不需要 RVO,因为它可能无法在每个调用约定中实现。