Reputation: 19033
Why so many calls to copy cons, i would expect only last nine of them? Or even not at all duy to return value optimization.
struct C
{
int _i;
C(int i) : _i(i) {}
C(const C& other) { cout << "copy cons from " << other._i << " to " << _i << endl; _i = other._i; }
};
int _tmain(int argc, _TCHAR* argv[])
{
vector<int> vi{ 1, 2, 3, 4, 5, 6, 7, 8, 9 };
vector<C> vc;
transform(vi.begin(), vi.end(), back_inserter(vc),
[](int i)
{
return C(i);
});
}
Output:
copy cons from 1 to - 842150451
copy cons from 1 to - 842150451
copy cons from 2 to - 842150451
copy cons from 1 to - 842150451
copy cons from 2 to - 842150451
copy cons from 3 to - 842150451
copy cons from 1 to - 842150451
copy cons from 2 to - 842150451
copy cons from 3 to - 842150451
copy cons from 4 to - 842150451
copy cons from 1 to - 842150451
copy cons from 2 to - 842150451
copy cons from 3 to - 842150451
copy cons from 4 to - 842150451
copy cons from 5 to - 842150451
copy cons from 6 to - 842150451
copy cons from 1 to - 842150451
copy cons from 2 to - 842150451
copy cons from 3 to - 842150451
copy cons from 4 to - 842150451
copy cons from 5 to - 842150451
copy cons from 6 to - 842150451
copy cons from 7 to - 842150451
copy cons from 8 to - 842150451
copy cons from 9 to - 842150451
Upvotes: 3
Views: 333
Reputation: 310980
As it is seen from the program output when a new element is added to the vector then the memory is reallocated and already existent elements of the vector are copied in new locations.
You can reserve enough memory before running the algorithm that to avoid memory reallocation.
vector<C> vc;
vc.reserve( vi.size() );
In this case redundent calls of the copy constructor could be avoided.
But it is not the full story.:)
Class C has a conversion constructor
C(int i) : _i(i) {}
It allows to simplify creating elements of vector vc
by substituting the call of the algorithm std::transform
that uses a lambda expression for algorithm std::copy
without using a lambda expression. For example
std::copy( vi.begin(), vi.end(), std::back_inserter( vc ) );
But even this is not the full story.:)
When you use either std::transform
or std::copy
then there are used two constructors: the constructor with a parameter and the copy construtor.
You could avoid using the copy construtor and achieve a more efficient result. Simply instead of method push_back
it is better to use method emplace_back
How to use this method?
The simplest one is to use the range-based for statement
for ( int x : vi ) vc.emplace_back( x );
It is enough clear and readable.
If you want to use a standard algorithm you could write
std::for_each( vi.begin(), vi.end(), [&vc]( int x ) { vc.emplace_back( x ); } );
In the both cases only the constructor with a parameter will be called avoiding calling the copy constructor.
Check it yourself.:)
Upvotes: 4
Reputation: 227410
Your vector vc
has to grow a few times. Each time it does that, it allocates a larger memory block, and copies the original elements over.
You can stop it from doing that by reserving enough space using std::vector::reserve
.
vector<C> vc;
vc.reserve(vi.size());
Upvotes: 10