Home > Mobile >  Move elements while reallocation elements in vector
Move elements while reallocation elements in vector

Time:05-15

I have the following code:

#include <vector>
#include <iostream>

struct Data
{
    Data() = default;

    Data(const Data& other)
    {
        std::cout << "copy ctr" << std::endl;
    }

    Data(Data&& other)
    {
        std::cout << "move ctr" << std::endl;
    }
};

int main(int argc, char** argv)
{
    std::vector<Data> vector;
    for (size_t i = 0u; i < 100u;   i) {
        vector.push_back(Data{});
    }

    return EXIT_SUCCESS;
}

With the following output:

move ctr move ctr copy ctr move ctr copy ctr copy ctr move ctr move ctr copy ctr copy ctr copy ctr copy ctr move ctr move ctr move ctr move ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr move ctr move ctr move ctr move ctr move ctr move ctr move ctr move ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr move ctr move ctr move ctr move ctr move ctr move ctr move ctr move ctr move ctr move ctr move ctr move ctr move ctr move ctr move ctr move ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr move ctr move ctr move ctr move ctr move ctr move ctr move ctr move ctr move ctr move ctr move ctr move ctr move ctr move ctr move ctr move ctr move ctr move ctr move ctr move ctr move ctr move ctr move ctr move ctr move ctr move ctr move ctr move ctr move ctr move ctr move ctr move ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr copy ctr move ctr move ctr move ctr move ctr move ctr move ctr move ctr move ctr move ctr move ctr move ctr move ctr move ctr move ctr move ctr move ctr move ctr move ctr move ctr move ctr move ctr move ctr move ctr move ctr move ctr move ctr move ctr move ctr move ctr move ctr move ctr move ctr move ctr move ctr move ctr

Why I have so much move operations???

My copy and move constructor aren't noexcept...

CodePudding user response:

This is due to reallocations of the storage for the std::vector. Each time you push_back, if the capacity of the container is not big enough, there's a reallocation. It requires a copy/move of all the current elements into the bigger storage.

There's a discussion here about using move constructor whenstd::vector grows: How to enforce move semantics when a vector grows?.

It is suggested there that adding noexcept will inform the std::vector to use move semantics (with some links to cppreference). I confirmed that is so in your case in MSVC.

In order to avoid it you can use std::vector::reserve. It will reserve storage for the push_backs.

Add the following line before the loop in your main:

vector.reserve(100u);

Now you'll see that only move constructor is called, once for each push_back.

CodePudding user response:

When std::vector needs more space, it allocates a new array and copies/moves all the existing elements from the old array to the new array. In your example, this reallocation may happen when push_back is used and the capacity of the old vector is not enough to hold all the elements(old new).

Solution 1
To minimize this, use the std::vector::reserve() member function before pushing elements onto the vector. This pre-allocates the needed space.

std::vector<Data> myVector;
myVector.reserve(100u);
for (size_t i = 0u; i < 100u;   i) {
        myVector.push_back(Data{});
    }

Solution 2
Or you can create the vector to be of a particular size, like:

std::vector<Data> myVector(100u); //create a vector of size 100 where all elements are default initialized

CodePudding user response:

I'm not sure what you expected. I counted your output like this:

$ foo | tr " " "\n" | sort | uniq -c
127 copy
227 ctr
100 move

You call vector.push_back 100 times with a temporary object. Since that is movable it gets forwarded to vector.emplace_back which in turn forwards the construction of the objects to "move ctr". 100 calls, 100 "move ctr". That's exactly the number of calls you should expect.

The only thing you should be asking about are the 127 calls to "copy ctr". Those are the bad ones. And the reason for them is that as you push elements into the vector it has to resize the storage. Since your class lacks a move assignment operator the objects have to be copied on resize. You should add Data & operator=(Data &&rhs) so elements can be moved.

You can avoid the resize altogether by making the vector big enough from the start:

vector.reserve(100);
  • Related