我想确保我的例程尽可能利用(N)RVO。除了解析生成的反汇编之外,还有什么我可以做或检查是否正在使用(N)RVO编译例程?在这一点上,我最感兴趣的是MSVC和GCC。
答案 0 :(得分:7)
不,不是真的。
但是,您可以在编写代码时遵循指南。
未命名的返回值优化
每次返回临时文件时都会触发此操作,即使在调试模式下也是如此。
return MyObject(....);
命名返回值优化
每次函数总是返回相同的临时对象时,这几乎都会触发:
MyObject func() {
MyObject result;
if (...) { return result; }
result.push(0);
return result;
}
你可以混合使用它们,但在这种情况下编译器几乎不可能应用RVO:
MyObject func() {
MyObject result;
if (...) { return MyObject(...); }
return result;
}
在这里,一个回归可能会受益于RVO而另一回不会受益。我敢打赌第一个被优化,因为如果你在返回槽中推测性地创建result
并且突然需要采用if
分支,你就会陷入困境。请注意,只需重新排序语句就可以了:
MyObject func() {
if (...) { return MyObject(...); }
MyObject result;
return result;
}
因此,NRVO的经验法则是return
声明和result
声明之间不应返回return result;
声明,而result
声明除了{{1}}之外还返回任何其他声明
如果你遵循这个,你就有可能对你有利。然后,这只是代码审查的问题。
并且您还可以使代码更容易阅读,因为在知道您确实需要变量之前不会声明变量!
答案 1 :(得分:2)
您可以向析构函数添加调试方法:
struct A
{
~A() { cout << "destructor called"; }
};
A foo()
{
A a;
return a;
}
如果调用析构函数,则可能未应用RVO。
答案 2 :(得分:1)
我能想到的可能方法是:
在你的类中实现一个引用计数机制,它跟踪通过类创建的实例的数量,就像shared_ptr
一样,这样你可以检测你的类的额外副本如果没有发生复制,则创建和删除。
您可以简单地将调试跟踪放在类的复制构造函数和析构函数中,如果没有发生复制省略,您会看到许多连续的复制构造函数和析构函数调试跟踪。