我如何确定例程正在利用 (N)RVO?
-
09-12-2019 - |
题
我想确保我的日常生活尽可能利用 (N)RVO。除了解析生成的反汇编结果之外,我还能做些什么或检查是否正在使用 (N)RVO 编译例程?目前我最感兴趣的是 MSVC 和 GCC。
解决方案
不,不是真的。
但是,您在编写代码时可以遵循准则。
未命名返回值优化
每次返回临时值时,这几乎都会被触发,即使在调试模式下也是如此。
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
本身。
如果你遵循这一点,你的胜算就会对你有利。然后这只是代码审查的问题。
而且您还可以使代码更易于阅读,因为您在知道确实需要变量之前不会声明变量!
其他提示
您可以向析构函数添加调试方法:
struct A
{
~A() { cout << "destructor called"; }
};
A foo()
{
A a;
return a;
}
.
如果调用析构函数,则可能未应用RVO。
我能想到的可能的方法有:
在类中实现引用计数机制,该机制跟踪通过类创建的实例的数量,这非常类似于
shared_ptr
这样,如果没有发生复制省略,您可以检测到正在创建和删除的类的额外副本。您可以简单地将调试跟踪放入类的复制构造函数和析构函数中,如果没有发生复制省略,您将看到许多连续的复制构造函数和析构函数调试跟踪。
不隶属于 StackOverflow