声明对象的性能

performance of declaring objects

当我在循环中声明地图时,我在某种大学征服中编码并注意到了一些东西,如下所示:

for (int i = 0; i < n; i++)
{
    map<int, bool> hashMap;
    //...
}

花费的时间比:

map<int, bool> hashMap;
for (int i = 0; i < n; i++)
{
    hashMap.clear();
    //...
}

所以我想知道为什么在循环中声明一个对象比重新初始化它的性能更差?

在代码的第一个版本中,hashMap 的构造函数和析构函数被调用 n 次,而在第二个版本中,它们仅被调用一次。

自然而然的问题是,为什么销毁和构建一个新的 map 对象与清除和重用同一个对象会有明显的不同。这只能通过检查正在使用的实现的实际 map 代码才能明确回答,因此以下只是一个似是而非的猜测。

std::map is usually implemented using red-black trees, and it is common for red-black tree implementations to use a sentinel node for NIL-leaves, see for example Benefit of a sentinel node in a red black tree?。每次构建树时都必须分配这个哨兵,然后在销毁时释放。相反,clear'ing a map,相反,清空树但重用关联的内部对象。

对于此类实现的真实示例,Microsoft 的 _Tree 构造函数调用恰当命名的 _Alloc_sentinel_and_proxy();。由于它们的 map 派生自 _Tree,因此每次构造 map 对象时都会调用它。