Why doesn't this code work? There is nothing about CopyConstructibility in the docs for the insert method of std::map: http://en.cppreference.com/w/cpp/container/map/insert
I can construct std::pair with the second element being my non_copyable class, but I cannot insert it into map, even though the very first overload of the insert method takes a const value_type&, so this should work fine.
Can someone help me understand why std::map requires this CopyConstructibility?
#include <utility>
#include <map>
struct non_copyable {
non_copyable(){}
private:
non_copyable(const non_copyable&);
};
int main() {
std::pair<int, non_copyable> p; // this works!
std::map<int, non_copyable> m;
m.insert(std::pair<int, non_copyable>()); // this does NOT work
}
... even though the very first overload of the insert method takes a const value_type& , so this should work fine.
No, actually in this case, the correct overload resolution candidate for:
m.insert(std::pair<int, non_copyable>());
is this overloaded member function:
template< class P >
std::pair<iterator,bool> insert( P&& value );
Now this page describes why this doesn't work:
... only participates in overload resolution if
std::is_constructible<value_type, P&&>::value == true
.
Your non_copyable
is not constructible:
using M = std::map<int, non_copyable>;
using P = std::pair<int, non_copyable>;
std::is_constructible<M::value_type, P&&>::value; // false
because there's no available constructor including a default, implicit move constructor generated by the compiler.
The reason non_copyable
even disabled its default, implicit move constructor is because of having a user-defined copy constructor, as documented :
If no user-defined move constructors are provided for a class type (struct, class, or union), and all of the following is true:
there are no user-declared copy constructors
there are no user-declared copy assignment operators
there are no user-declared move assignment operators
there are no user-declared destructors
Now giving non_copyable
a move constructor becomes your responsbility:
struct non_copyable {
non_copyable(){}
non_copyable(non_copyable &&) = default;
private:
non_copyable(const non_copyable&);
};
You may be interested why you have to make any copies at all hence provide copy constructible types even if you could construct a pair directly (emplace it) inside of a map.
It is because to provide the required performance the internal representation of the std::map is usually implemented as a balanced binary search tree (eventually as another data structure with similar performance characteristics) requiring some specific order of stored elements. So after adding or deleting some elements the order may be broken and to preserve its correctness occasional internal moves of the stored elements will be needed.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.