Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

Tags:

c++

vector

move

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;
}
like image 851
Mindaugas Kasiulis Avatar asked Jan 01 '23 00:01

Mindaugas Kasiulis


2 Answers

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!

like image 143
druckermanly Avatar answered Jan 05 '23 17:01

druckermanly


Please take a look at this post: STL vector: Moving all elements of a vector

std::move() is an O(1) solution. When you use ith on vectors, the moved vector is now empty, and the new one has all elements of moved one. The reserve() methods will do not anything in this case (but in other cases it's very useful).

You can use std::swap() method, which is also a method that doesn't need using the reserve() method.

like image 45
Raffallo Avatar answered Jan 05 '23 17:01

Raffallo