Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When is a vector copied, when is a reference passed?

Tags:

c++

stl

stdvector

I'm working with a program that makes use of std::vector a lot. Also there are lots of allocations/deallocations taking place, billions of them, and I'm trying to avoid as many of them as possible. Since I'm relatively new to C++, I have a few questions regarding allocations taking place when using a vector (e.g. when adding elements to it). I'm on a Win7 64-bit machine, the program is 32-bit and I'm using the current version of MinGW-compilers.

I'd like to know, what happens in the following cases, i.e. if the vector is copied, passed as a reference, ...

1.

std::vector<T> fillVector() {
    std::vector<T> returnVector;
    ...
    return returnVector;
}

std::vector<T> myVector = fillVector();

2.

 std::vector<T>& fillVector() {
    std::vector<T>* returnVector = new std::vector<T>;
    ...
    return (*returnVector);
}

std::vector<T> myVector = fillVector();

3.

std::vector<T>* fillVector() {
    std::vector<T>* returnVector = new std::vector<T>;
    ...
    return returnVector;
}

std::vector<T>* myVector = fillVector();

And the following, different operations:

4.

std::vector<T> myVector1;
... (myVector1 being filled)
std::vector<T> myVector = myVector1;

5.

std::vector<T>* myVector1 = new std::vector<T>;
... (myVector1 being filled)
std::vector<T> myVector = (*myVector1);

Assuming I don't want to change the argument in myFunction/changes in to myVector in myFunction wouldn't hurt the rest of the program:

6.

void myFunction(std::vector<T> myParam) {
   ...
}

std::vector<T> myVector;
... (myVector being filled)
myFunction(myVector);

7.

void myFunction(std::vector<T>& myParam) {
   ...
}

std::vector<T> myVector;
... (myVector being filled)
myFunction(myVector);

If my understanding is correct, the fastest options (meaning passing references instead of creating copies and passing them) would be 2/3, 5 and 7. Please correct me if I'm wrong!

like image 982
MrWayne Avatar asked Feb 27 '13 19:02

MrWayne


1 Answers

1.

std::vector<T> fillVector() {
    std::vector<T> returnVector;
    ...
    return returnVector;
}

std::vector<T> myVector = fillVector();

This is fine. The vector is returned by value, but the call to the copy constructor is elided by most compilers (at least when optimizations are turned on) under the (Named) Return Value Optimization.

Moreover, with C++11, move semantics makes sure the move constructor is invoked rather than the copy constructor, which will simply steal the guts of the returned vector without generating an expensive copy.

2.

 std::vector<T>& fillVector() {
    std::vector<T>* returnVector = new std::vector<T>;
    ...
    return (*returnVector);
}

std::vector<T> myVector = fillVector();

Don't do this. Unnecessary overhead of the dynamic allocation, plus the burden of having to remember that you have to deallocate the returned object. Avoid manual memory management and prefer 1.

3.

std::vector<T>* fillVector() {
    std::vector<T>* returnVector = new std::vector<T>;
    ...
    return returnVector;
}

std::vector<T>* myVector = fillVector();

Same as above. Avoid manual memory management.

4.

std::vector<T> myVector1;
... (myVector1 being filled)
std::vector<T> myVector = myVector1;

This is a conceptually different operation. Here you want to create a copy, and it seems you're doing it right. In C++11 you might want to use std::vector<T> myVector = std::move(myVector1) if all you need is transfer the contents of myVector1 rather than copying it.

5.

std::vector<T>* myVector1 = new std::vector<T>;
... (myVector1 being filled)
std::vector<T> myVector = (*myVector1);

Same as above, you want to create a copy, but you are unnecessarily allocating the vector dynamically. This again will force you to take care of its lifetime manually, which is bad and error-prone. Don't do this.

6.

void myFunction(std::vector<T> myParam) {
   ...
}

std::vector<T> myVector;
... (myVector being filled)
myFunction(myVector);

Here you are passing myVector by value. Whether or not this can be optimize depends on what myFunction is suppopsed to do with its argument: shall it change it? If so, do you want these changes to be visible after returning from the function? If yes, passing by value is correct and there is no way to optimize it unless you want to get ride of the myVector object: in that case, in C++11 you can move it when passing it to the function. This will avoid an expensive, unnecessary copy.

7.

void myFunction(std::vector<T>& myParam) {
   ...
}

std::vector<T> myVector;
... (myVector being filled)
myFunction(myVector);

This will pass by reference, and it is OK as long as it is fine to see the side-effects of myFunction on myVector after returning from the function. It can't be told in general whether that's correct or not, it depends on the particular logic of your application.

like image 73
Andy Prowl Avatar answered Oct 04 '22 20:10

Andy Prowl