srm*_*srm 5 c++ stl new-operator
如果您使用带有值类型的C++ std :: map(和其他容器),您会注意到插入到地图中会调用元素类型的析构函数.这是因为C++规范要求operator []的实现等效于:
(*((std::map<>::insert(std::make_pair(x, T()))).first)).second
Run Code Online (Sandbox Code Playgroud)
它调用您的类型的默认构造函数以构建该对.然后将该临时值复制到地图中,然后进行破坏.可以在此stackoverflow帖子和codeguru中找到对此的确认.
我发现奇怪的是,这可以在不需要临时变量的情况下实现,但仍然是等效的.C++的一个特性叫做"inplace new".std :: map和其他容器可以为对象分配空的空间,然后在分配的空间上显式调用元素的默认构造函数.
我的问题:为什么我所见过的std :: map的实现都没有使用new来优化这个操作?在我看来,它将大大提高这种低级别操作的性能.但很多人都研究过STL代码库,所以我认为必须有这样的原因.
一般来说,像较低级别的操作一样指定较高级别的操作[]是一个好主意。
在 C++11 之前,[]如果不使用insert.
在 C++11 中,添加了std::map<?>::emplacefor 和类似的东西std::pair使我们能够避免这个问题。如果您重新定义它并使用这种就地构造,则额外的(希望被省略的)对象创建将会消失。
我想不出有什么理由不这样做。我鼓励您提出标准化建议。
为了演示对 a 的无复制插入std::map,我们可以执行以下操作:
#include <map>
#include <iostream>
struct no_copy_type {
no_copy_type(no_copy_type const&)=delete;
no_copy_type(double) {}
~no_copy_type() { std::cout << "destroyed\n"; }
};
int main() {
std::map< int, no_copy_type > m;
m.emplace(
std::piecewise_construct,
std::forward_as_tuple(1),
std::forward_as_tuple(3.14)
);
std::cout << "destroy happens next:\n";
}
Run Code Online (Sandbox Code Playgroud)
现场示例——如您所见,没有生成临时文件。
所以如果我们替换
(*((std::map<>::insert(std::make_pair(x, T()))).first)).second
Run Code Online (Sandbox Code Playgroud)
和
(*
(
(
std::map<>::emplace(
std::piecewise_construct,
std::forward_as_tuple(std::forward<X>(x)),
std::forward_as_tuple()
)
).first
).second
Run Code Online (Sandbox Code Playgroud)
不会创建临时文件(添加空格以便我可以跟踪()s)。