c++ std transform calls copy constructor multiple times

The element type in a std::map is std::pair<const Key, Value>.

In your example use use std::pair<int, A> without const, so you need to copy the pair. This adds a copy in the first two solutions. If you change it to std::pair<const int, A> you can see 2 constructor calls in the first iteration and only one in the second (on par with your for loop).

For the first iteration you now have 1 copy and one move. This is because your lambda needs to copy the A then back_inserter move constructs it into the vector. Normally I wouldn’t worry about an extra move since they are supposed to be cheap.

However, you can get rid of it. We can force the lamba to not copy the A instance, by ,for example, specifying the return type to be a reference. So now the back_inserter will have to copy when it inserts, but that’s it.

This version of your code does one copy per element for each solution:

std::map<int, A> m; m.insert(std::make_pair(0, A(7))); m.insert(std::make_pair(1, A(3))); m.insert(std::make_pair(2, A(1)));  std::vector<A> vec;

std::cout << "Transform" << std::endl;

vec.reserve(m.size());
std::transform(m.begin(), m.end(), std::back_inserter(vec),
     // changed the key type and return type.
     [](const std::pair<const int, A> & p)->const A& { return p.second; }); 

std::cout << "for_each" << std::endl;
vec.resize(0);
vec.reserve(m.size());
std::for_each(m.begin(), m.end(),
    // changed the key type.
    [&vec](const std::pair<const int, A> & p) { vec.push_back(p.second); });

std::cout << "START\n";
vec.resize(0);
vec.reserve(m.size());

for (const auto & p : m) {
    vec.emplace_back(p.second);
}

CLICK HERE to find out more related problems solutions.

Leave a Comment

Your email address will not be published.

Scroll to Top