我讲述了一个令人沮丧的旅程的故事,我发现我从一个函数返回的无序地图实际上并不是RVO,即使我确定它是在较早的时间它是无关紧要的.
有没有办法检查RVO是否在任何给定的函数中发生?或者像一个做的列表并且不要遵循以获得我想要的结果?
是的。为类的生命周期方法创建钩子:
#include <iostream>
struct A{
A()
{ std::cout<<"Ctor\n"; }
A(const A& o)
{ std::cout<<"CCtor\n"; }
A(A&& o)
{ std::cout<<"MCtor\n"; }
~A()
{ std::cout<<"Dtor\n"; }
private:
int vl_;
};
A getA(){
A a;
return a;
}
int main(){
A b = getA();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
现在使用 RVO,b 和ain是同一个对象,getA所以你只会看到
Ctor
Dtor
Run Code Online (Sandbox Code Playgroud)
您可以抑制 RVO,例如,通过添加额外的返回点:
return a;
return A{a};
Run Code Online (Sandbox Code Playgroud)
或移动:
return std::move(a);
Run Code Online (Sandbox Code Playgroud)
然后你会看到:
Ctor
Mctor
Dtor
Dtor
Run Code Online (Sandbox Code Playgroud)
您可以验证 RVO 是否已在对您重要的所有地方使用:
template<typename T>
struct force_rvo: T {
force_rvo() {}
using T::T;
force_rvo(const force_rvo &);
force_rvo(force_rvo &&);
};
force_rvo<std::map<int, int>> f() {
force_rvo<std::map<int, int>> m;
m[17] = 42;
return m;
}
int main() {
auto m = f();
return m[42];
}
Run Code Online (Sandbox Code Playgroud)
该force_rvo类型假装是可复制和可移动的,否则编译器将拒绝return m。但如果实际使用其中任何一个,链接器将失败并告诉您到底发生在哪里。包装器是零成本的,但需要在调用方和实现方都使用它,这可能不是很方便。