Move contruct `std::map` from a different container
Asked Answered
F

2

5

I want to convert a temporary container to a std::map<S, T>.

Let's say the temporary container is a std::unordered_map<S, T>, with T move-constructible.

My question is: (how) can I use move contructor of std::map<S, T>?

For a simplified case, consider

#include <bits/stdc++.h>
using namespace std;

template<typename S, typename T>
map<S, T>
convert(unordered_map<S, T> u)
{
    // Question: (how) can I use move constructor here?
    map<S, T> m(u.begin(), u.end());
    return m;
}

int main()
{
    unordered_map<int, int> u;

    u[5] = 6;
    u[3] = 4;
    u[7] = 8;

    map<int, int> m = convert(u);

    for (auto kv : m)
        cout << kv.first << " : " << kv.second << endl;

    return 0;
}

The output is

3 : 4
5 : 6
7 : 8

Of course, in a more complex setting, S and T are not int.

Thank you very much.

Update Thank you all for instant and valuable replies! I appreciate the observation that map is intrinsically different in data structure from an unordered_map. So if move cannot happen at the container level, I would also accept move at the element level. Just want to make sure and know how.

Foilsman answered 15/10, 2018 at 5:25 Comment(1)
answers here would be your best betMitra
E
14

Let's say the temporary container is a std::unordered_map, with T move-constructible.

If you wish to move your values whose type is movable T, instead of copy-ing, try using std::move_iterator as follows:

map<S, T> m(std::make_move_iterator(u.begin()), std::make_move_iterator(u.end()));

Example

#include <iostream>
#include <map>
#include <unordered_map>
#include <iterator>


struct S
{
    bool init = true;
    static int count;
    S() { std::cout << "S::S() " << ++count << "\n"; }
    S(S const&) { std::cout << "S::S(S const&)\n"; }
    S(S&& s) { std::cout << "S::S(S&&)\n"; s.init = false; }
    ~S() { std::cout << "S::~S() (init=" << init << ")\n"; }
};

int S::count;


int main()
{
    std::cout << "Building unordered map\n";
    std::unordered_map<int, S> um;
    for (int i = 0; i < 5; ++i)
        um.insert(std::make_pair(i, S()));

    std::cout << "Building ordered map\n";
    std::map<int, S> m(
        std::make_move_iterator(um.begin()), 
        std::make_move_iterator(um.end()));
}

Output

Building unordered map
S::S() 1
S::S(S&&)
S::S(S&&)
S::~S() (init=0)
S::~S() (init=0)
S::S() 2
S::S(S&&)
S::S(S&&)
S::~S() (init=0)
S::~S() (init=0)
S::S() 3
S::S(S&&)
S::S(S&&)
S::~S() (init=0)
S::~S() (init=0)
S::S() 4
S::S(S&&)
S::S(S&&)
S::~S() (init=0)
S::~S() (init=0)
S::S() 5
S::S(S&&)
S::S(S&&)
S::~S() (init=0)
S::~S() (init=0)
Building ordered map
S::S(S&&)
S::S(S&&)
S::S(S&&)
S::S(S&&)
S::S(S&&)
S::~S() (init=1)
S::~S() (init=1)
S::~S() (init=1)
S::~S() (init=1)
S::~S() (init=1)
S::~S() (init=0)
S::~S() (init=0)
S::~S() (init=0)
S::~S() (init=0)
S::~S() (init=0)
Elga answered 15/10, 2018 at 5:49 Comment(1)
This answer is full of win and dripping with awesome. I keep forgetting this was added in C++11. Feel free to snatch up and modify this example for your answer. It clearly demonstrates N actual constructions, then just a ton of moves and proper destruction of both moved-to and moved-from objects. No copies.Audwin
P
0

No, you cannot move-construct a std::map<S, T> from an std::unordered_map<S, T>.

Pillowcase answered 15/10, 2018 at 5:36 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.