Why does the map.insert() method invoke the copy constructor twice?

匆匆过客 提交于 2021-02-19 02:39:08

问题


I'm creating the custom class Node in order to implement a binary tree using a map<int,Node> container: the int key of the map is the identifier of a Node object. In the class Node I had to implement a copy constructor.

When inserting a Node object on the map, I noticed that the copy constructor of the Node is invoked twice. Why?

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);

Running the above code, the output is as follows:

node2
--- Node()
map
toInsert
--- Node(const Node& orig)
insert
--- Node(const Node& orig)   // Why does the copy constructor be invoked twice?
--- Node(const Node& orig)   // ------------------------------------------------
--- ~Node()
--- ~Node()
--- ~Node()
--- ~Node()

回答1:


Most likely because the value type of your map is pair<int const, Node>, not pair<int, Node>: in a map, the key is constant.

Since insert() accepts a pair<int const, Node> const& and you supply a pair<int, Node>, to perform the conversion a temporary must be constructed from which the value in the map can in turn be copy-constructed.

To verify it, change this line:

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

Into this line:

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

And you should see the extra call to the copy constructor disappear.

Also keep in mind, that the concrete implementation of Standard Library containers are not required to perform a particular number of copies: implementations may vary, and different optimization levels could make things different as well.




回答2:


You are using pair<int,Node>. The type taken by the insert method is map<K,V>::value_type which is defined as pair<const K,V>. The compiler must insert an additional copy to convert between these two types.

Try using map<int,Node>::value_type instead of pair<int,Node>. It is better to use the types defined by the class itself rather than recreating them from scratch.

You can also avoid your first copy by writing.

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

instead of

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



回答3:


When you do the following:

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

You are passing the node2 into the constructor of the pair object. Even though you are passing by reference, conceptually you are binding the values together, and that means the pair object is making a copy of the node2 object. Copy #1.

When you pass this pair object to the insert function:

mapping.insert(toInsert);

.. yes you are passing by reference, but the container doesn't know anything about the lifetime of the object referenced (toInsert). So it makes it's own copy to store in the container. Copy #2.



来源:https://stackoverflow.com/questions/15247262/why-does-the-map-insert-method-invoke-the-copy-constructor-twice

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!