I have a std::map which contains a bunch of key value pairs. I want move these elements into a std::vector. I tried using std::transform from <algorithm> to do this, but it doesn't work. Here's my code:
#include <algorithm>
#include <cstdint>
#include <iostream>
#include <map>
#include <vector>
struct Values
{
uint32_t a = 0;
uint32_t b = 0;
Values(uint32_t x, uint32_t y): a(x), b(y) {}
};
template <typename MapType>
auto foo(MapType&& map)
{
std::vector<typename MapType::value_type> v;
v.reserve(map.size());
std::transform(map.begin(), map.end(), std::back_inserter(v), [](const auto& kv) -> decltype(auto) { return std::move(kv); });
std::cout << map.size() << " " << v.size() << "\n";
}
int main()
{
std::map<uint32_t, Values> data;
for(uint32_t i = 0; i < 100; i++)
data.emplace(std::piecewise_construct, std::forward_as_tuple(i), std::forward_as_tuple(2*i, 3*i));
foo(std::move(data));
return 0;
}
I'm compiling this code using gcc:
g++ -std=c++23 -Ofast -Wall -Wextra -Wpedantic -Wconversion -Werror main.cpp
Here's the link to compiler explorer.
The program outputs the number of elements in the std::map and std::vector after the call to std::transform. The output that I get is:
100 100
This tells me that instead of the elements being moved, they we just copied into the vector. How can I change this code to use move instead.
You can get close with something like this:
for (auto it = map.begin(); it != map.end(); /*no increment*/) {
auto node = map.extract(it++);
v.emplace_back(std::move(node.key()), std::move(node.mapped()));
}
This should involve only move constructors on both key and value objects, and no copy constructors (for those classes where the two are distinct, of course; in your example, moving and copying are equivalent). It will leave the map empty at the end.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With