0
votes

I have a question about std::vector initialization, but can't find a simple solution.

Imagine we have a vector with some data and a map function which should be applied to each element of this vector and these new values should be pushed back to another vector.

std::vector<int> vector1{10, 20, 30};
auto map = [](int v) { return v * 2; } // double each value
std::vector<int> vector2{...} // there should be 20, 40, 60 as a result

Looks easy to do? But I want to do this with 100% efficiency:

  1. Output vector should be resized to input vector size before insertion (repeated push_back will check vector capacity each time and this is inefficient)

  2. There should be no zero initialization of new vector data before initialization with mapped elements. For example, vector::resize will zero initialize the new vector, which I want to void.

I have a solution using custom iterator and disassembly looks efficient. But maybe I missed something and some standard solution exists.

2
there is std::vector::reserve463035818_is_not_a_number
the zeroing will often be subsequently optimized away by the compiler if you then overwrite the content straight away. Also, don't overestimate the effort that zeroing really is.Marcus Müller
I know that there is std::vector::reserve, yes, it doesn't initialize the data, but also doesn't change the size.mdr
when you say "will check vector capacity each time" you mean it will have to check if adding one element needs more capacity even though capacity is sufficient? Might be that I misread the question slightly.463035818_is_not_a_number
I don't think there's an easier solution that is as performant as the one you have with the custom iterator. Alternatively you can write a custom vector class, use a raw array, or just program in C.rustyx

2 Answers

0
votes

You can use reserve which merely reserves capacity but does not construct elements. To transform one vector to another you can use std::transform with a std::back_inserter:

#include<vector>
#include<algorithm>
#include <iostream>
#include <iterator>
int main()
{
    std::vector<int> vector1{10, 20, 30};
    auto map = [](int v) { return v * 2; }; // double each value
    std::vector<int> vector2; // there should be 20, 40, 60 as a result
    vector2.reserve(vector1.size());
    std::transform(vector1.begin(),vector1.end(),std::back_inserter(vector2),map);
    for (const auto& e : vector2) std::cout << e << " ";
}

I am not sure if using emplace instead of the back_inserter would be more efficient. Unfortunately there is nothing like a back_emplacer, so you would need to write a manual loop. For ints it certainly won't make a difference.

0
votes

You could just create vector2 with a given size, then fill it with std::transform.

You could as well reuse vector1 if you are no longer going to use it.

https://godbolt.org/z/GsroG1WeG

#include <algorithm>
#include <iostream>
#include <vector>

int main()
{
    std::vector<int> vector1{10, 20, 30};
    std::vector<int> vector2(vector1.size());
    std::transform(cbegin(vector1), cend(vector1), begin(vector2), [](auto n){ return n*2; });
    std::copy(cbegin(vector2), cend(vector2), std::ostream_iterator<int>(std::cout, " "));
}