为什么map.insert()方法会两次调用复制构造函数?

时间:2013-03-06 12:23:10

标签: c++ map copy-constructor

我正在创建自定义类Node,以便使用map<int,Node>容器实现二叉树:地图的int键是{{1}的标识符对象。在类Node中,我必须实现一个复制构造函数。

在地图上插入Node对象时,我注意到Node的复制构造函数被调用了两次。为什么呢?

Node

运行上面的代码,输出如下:

cout << "node2" << endl;
Node node2;
node2.set_depth(2);
node2.make_it_branch(3,4);

cout << "map" << endl;
map<int,Node> mapping;
cout << "toInsert" << endl;
pair<int,Node> toInsert = pair<int,Node>(2,node2);
cout << "insert" << endl;
mapping.insert(toInsert);

3 个答案:

答案 0 :(得分:13)

最有可能的原因是地图的值类型为pair<int const, Node>,而非pair<int, Node>:在地图中,键是常量

由于insert()接受pair<int const, Node> const&并且您提供pair<int, Node>,因此要执行转换,必须构建临时值,然后可以从中复制构造映射中的值。

要验证它,请更改以下行:

pair<int, Node> toInsert = pair<int, Node>(2, node2);

进入这一行:

pair<int const, Node> toInsert = pair<int const, Node>(2, node2);

你应该看到对复制构造函数的额外调用消失了。

另外请记住,标准库容器的具体实现不需要执行特定数量的副本:实现可能会有所不同,不同的优化级别也可能会使事情变得不同。

答案 1 :(得分:1)

您正在使用pair<int,Node>。 insert方法采用的类型为map<K,V>::value_type,定义为pair<const K,V>。 编译器必须插入一个额外的副本才能在这两种类型之间进行转换。

尝试使用map<int,Node>::value_type代替pair<int,Node>。最好使用类本身定义的类型,而不是从头开始重新创建它们。

您也可以通过写作来避免您的第一份副本。

map<int,Node>::value_type toInsert(2,node2);

而不是

map<int,Node>::value_type toInsert = map<int,Node>::value_type(2,node2);

答案 2 :(得分:-1)

执行以下操作时:

toInsert = pair<int, Node>(2, node2);

您正在将node2传递给pair对象的构造函数。即使您通过引用传递,从概念上讲,您将绑定在一起,这意味着pair对象正在复制node2对象。复制#1。

将此pair对象传递给插入函数时:

mapping.insert(toInsert);

..是的,您通过引用传递,但容器不知道引用的对象(toInsert)的生命周期。所以它使它自己的副本存储在容器中。复制#2。