【发布时间】:2011-08-18 23:23:49
【问题描述】:
我正在为非 STL 容器类型实现自定义迭代器,并遇到了以下行为,在这个阶段,这对我来说似乎有点出乎意料。
当您定义“空”dtor 时,似乎会对性能产生重大影响?为什么??
为了深入了解这一点,我为 std::vector 实现了一个简单的迭代器,这样我就可以直接将性能与标准 STL 迭代器进行比较。为了公平测试,我只是从“vector.hpp”中复制了一个简化的实现,并尝试添加一个额外的“空”dtor:
template <typename _Myvec>
class my_slow_iterator // not inheriting from anything!!
{
public :
_Myvec::pointer _ptr; // pointer to vector element
/* All of the standard stuff - essentially from "vector.hpp" */
/* An additional empty dtor */
~my_slow_iterator () {}
};
然后我修改了 std::vector 以便我可以让它返回我的新迭代器类型并使用以下内容进行基准测试 - 对包含 2000000 个随机整数的向量进行排序,平均运行 3 次:
std::vector vec;
// fill via rand();
int tt = clock();
std::sort(vec.begin(), vec.end());
tt = clock() - tt; // elapsed time in ms
我得到了以下结果(VS2010、Release build、_ITERATOR_DEBUG_LEVEL 0 等):
- 使用标准 STL 迭代器:550 毫秒。
- 使用
my_slow_iterator并删除空 dtor:560 毫秒。 - 将
my_slow_iterator与包含的空 dtor 一起使用:900 毫秒。
在这种情况下,空的 dtor 似乎导致了大约 40% 的减速。
显然,如果 dtor 是空的,那么为什么要拥有它,但我期待像这样的简单“空”函数会在编译时内联并优化掉。如果不是这种情况,那么我想了解发生了什么,以防此类问题在更复杂的情况下产生影响。
编辑:使用 O2 优化编译。
编辑:再深入一点,复制 ctor 似乎也出现了类似的效果。最初(在上面的测试中)my_slow_iterator 没有定义 copy-ctor,因此使用编译器生成的默认值。
如果我定义了以下copy-ctor(它的作用并不比我预期的编译器生成的要多):
my_slow_iterator (
const my_slow_iterator<_Myvec> &_src
) : _ptr(_src._ptr) {}
对于与上述相同的测试,我看到以下结果:
- 使用
my_slow_iterator,删除dtor,包括copy-ctor:690ms - 使用
my_slow_iterator,包括dtor,包括copy-ctor:980ms
这是对性能的进一步影响(尽管没有那么剧烈)。
为什么/如何编译器默认函数如此高效?用户定义的 ctor/dtor 是否在后台隐式执行某些操作?
【问题讨论】:
-
发布版本,是的,但是是否开启了优化?您应该查看源代码/程序集列表 (/FAs) 以了解实际生成的内容:msdn.microsoft.com/en-us/library/367y26c6(v=vs.71).aspx
-
O2 优化,当然!我有点犹豫是否试图理解来自我的 std::sort 基准的汇编程序,但我想我可以尝试将其分解为对 dtor 的一次调用。
-
按照建议将
throw()添加到空 dtor 似乎没有帮助 -
@Darren,
_Myvec::pointer真的只是一个原始指针吗? -
@Doug:我把那行改成
_Myvec::value_type *_ptr只是为了确定,似乎没什么区别...