问题
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