Yola
Yola

Reputation: 19033

why so many copying while transforming/copying vector

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

Answers (2)

Vlad from Moscow
Vlad from Moscow

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

juanchopanza
juanchopanza

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

Related Questions