Difference between std :: pair and map :: value_type with unique_ptr

In the following code example, I am experimenting with std :: unique_ptrs. I can add unique_ptr to the map, as expected. Surprisingly, I cannot make him a member of std :: pair. The commented lines in the example should try to build a pair that has the same type (I think ...) as my map :: value_type. I am not sure why this is not working.

Thanks in advance.

#include <iostream> #include <memory> #include <map> #include <arpa/inet.h> typedef std::map<uint32_t, std::unique_ptr<uint32_t> > ntohl_map_type; typedef std::map<uint32_t, uint32_t> u32_map_type; void u32_map() { uint32_t key(0); uint32_t val(0); u32_map_type u32_map; u32_map.insert(u32_map_type::value_type(key, val)); u32_map.insert(std::pair<uint32_t, uint32_t>(++key, ++val)); std::cout << "u32_map: " << std::endl; for (auto &itr : u32_map) { std::cout << itr.first << " = " << itr.second << "\n"; } std::cout << std::endl; } void uptr_map() { uint32_t key(9); std::unique_ptr<uint32_t> u32_uptr1(new uint32_t(ntohl(key))); ntohl_map_type ntohl_map; ntohl_map.insert(ntohl_map_type::value_type(key, std::move(u32_uptr1))); ++key; std::unique_ptr<uint32_t> u32_uptr2(new uint32_t(ntohl(key))); // It seems odd these don't work.... //foo = std::pair<uint32_t, std::unique_ptr<uint32_t>(key, std::move(u32_uptr2)); //ntohl_map.insert(std::pair<uint32_t, std::unique_ptr<uint32_t>(key, std::move(u32_uptr2))); std::cout << "uptr_map: " << std::endl; for (auto &itr : ntohl_map) { std::cout << itr.first << " = " << *itr.second << "\n"; } } int main() { u32_map(); uptr_map(); return 0; } 

EDIT: Just realized that a compiler error would probably be useful:

 error: no matching constructor for initialization of 'std::unique_ptr<uint32_t>' ...const, std::unique_ptr<uint32_t>(key, std::move(u32_uptr2))); ^ ~~~~~~~~~~~~~~~~~~~~~~~~~ /usr/bin/../lib/c++/v1/memory:2554:31: note: candidate constructor not viable: no known conversionfrom 'uint32_t' (aka 'unsigned int') to 'pointer' (aka 'unsigned int *') for 1st argument; take the address of the argument with & _LIBCPP_INLINE_VISIBILITY unique_ptr(pointer __p, typename conditional< ^ /usr/bin/../lib/c++/v1/memory:2561:31: note: candidate constructor not viable: no known conversion from 'uint32_t' (aka 'unsigned int') to 'pointer' (aka 'unsigned int *') for 1st argument; take the address of the argument with & _LIBCPP_INLINE_VISIBILITY unique_ptr(pointer __p, typename... 
+4
source share
1 answer

You forget that the map key is constant (to prevent intentional or accidental messing with the internal ordering of the associative container):

 ntohl_map.insert( std::pair<uint32_t const, std::unique_ptr<uint32_t>>( // ^^^^^ key, std::move(u32_uptr2))); 

To avoid the error, you could do:

 ntohl_map.insert(ntohl_map_type::value_type(key, std::move(u32_uptr2))); 

The reason the original insert() call from your question text does not compile is because the type of the pair you provide is different from the type of the pair that insert() accepts (due to this const ), it should happen conversion, which will lead to an attempt to copy-create a temporary pair from the one you provide.

Copy-pairing means copying your elements, and since std::unique_ptr not constructive for copying, your program will not compile.

The reason that compiling a function using map<uint32_t, uint32_t> is because uint32_t (obviously) possible to copy.

Also note that since C ++ 11 std::map has a member function emplace() (which some implementations do not yet provide, so this may be your case), which allows you to create your own elements in place:

  ntohl_map.emplace(key, std::move(u32_uptr2)); 
+6
source

Source: https://habr.com/ru/post/1485195/


All Articles