Search code examples
c++vectormove

Is it possible to improve code performance by using reserve() before moving a vector with a bigger size into a vector with a smaller capacity?


sorry in advance if this question is quite incomplete, unclear or a duplicate (it's my first one here). While studying move semantics and working on a small project for my OOP course I stumbled upon a question that I can't answer myself. As far as I know std::move() works by converting l-values into r values, but let's suppose we were moving a vector with a lot of elements into a second vector that has a capacity of 1. Could I use reserve() to avoid a lot of automatic memory re-allocations of the second vector or would using reserve() have no effect due to std::move() moving r-values into the second vector? A simple realization of my question can be found below.

#include <iostream>
#include <vector>
#include <algorithm>
int main() {
    std::vector<int> first (1000000);
    std::vector<int> second (1);
    std::fill(first.begin(),first.end(),7);
    second.reserve(1000000);//is this needed??
    second=std::move(first);
    return 0;
}

Solution

  • No, that is not needed, and is almost certainly premature optimization.

    A vector really can be represented by 3 pointers (or two pointers and an offset, or one pointer and two offsets... but those aren't so common, so for the rest of my explanation I'll imagine vectors are represented by three pointers).

    1. One pointer points to the start of the memory it manages.
    2. One pointer points to one-past-the-end of the items that have been inserted in it.
    3. One pointer points to one-past-the-end of the memory it manages.

    A move constructor std::vector<int> a = std::move(b); could be implemented by just taking those three pointers from b, setting them to some easy-to-make value (nullptr as a sentinel value meaning "I'm empty", for example) and then everything would be done.

    In fact, this is how gcc does it (and most standard library implementations... but I had the gcc source handy). See here.

    So your reserve call is at best optimized by the compiler into a no-op, and at worst, is causing an unnecessary memory allocation. No good!