nowi
nowi

Reputation: 487

Constructing unordered_map always copies unique_ptr

For some reason, when trying to construct an unordered map (specifically by a pair), the map tried to copy the unique_ptr in the pair instead of move it. What am I doing wrong?

Here is an example (updated):

#include <unordered_map>
#include <memory>

class pointed
{
    bool x;
    int y;
public:
    float key;
    pointed( float key, bool x, int y ): x(x), y(y)
    { }
};

class test
{
    std::unordered_map< float, std::unique_ptr< pointed > > my_map;
public:
    template< typename... pointed_construction_t >
    test( pointed_construction_t &&... pointed_parameter_pack ):
        my_map
        {
            std::move
            (
                std::make_pair
                ( 
                    pointed_parameter_pack.key,
                    std::move
                    (
                        std::make_unique< pointed >
                        (
                            std::forward< pointed_construction_t >
                            ( 
                                pointed_parameter_pack 
                            )
                        ) 
                    )
                )
            )...
        }
    { }
};

int main( )
{
    float key = 2.f, key2 = 4.f;
    bool x = true, x2 = false;
    int y = 0, y2 = -1;
    test t( pointed( key, x, y ), pointed( key2, x2, y2 ), pointed( 6.f, false, 500 ) );
}

error: use of deleted function

note: declared here

406 | unique_ptr(const unique_ptr&) = delete;

Upvotes: 0

Views: 294

Answers (1)

David G
David G

Reputation: 96845

Using my_map{...} is list-initialization and the compiler finds the std::initializer_list constructor of std::unordered_map. This constructs an initializer list which holds an array of const elements. So your elements can't be moved from the list to the map.

You'll have to go inside the constructor and emplace the elements of the pair:

test(int key, pointed_construction_t&&... pointed_parameter_pack) {
  map.emplace(key,
              std::make_unique<pointed>(std::forward<pointed_construction_t>(
                  pointed_parameter_pack)...));
}

With your new update I am able to understand what you want. Use a fold expression so that emplace is called for every pointed argument.

(map.emplace(key,
         std::make_unique<pointed>(
             std::forward<pointed_construction_t>(pointed_parameter_pack))),
...);

Upvotes: 1

Related Questions