Pergunta

Suppose I create two vectors, one on the heap and one on the stack:

Vector<int> vector1;
Vector<int>* vector2 = new Vector<int>;

I then pass vector1 into two functions, say, foo1(Vector<int>) and foo2(Vector<int>&). I also pass vector2 into foo3(Vector<int>*).

Since I'm new to C++, I'm rather confused by the difference in behaviours here.

  1. Am I right to say that for foo1, the entire vector1 gets copied, and for foo2, only the reference to vector1 gets passed into the function?

  2. But isn't vector1, declared on the stack, supposed to be inaccessible anywhere else (i.e. from inside foo2) except the scope in which it was created?

  3. Also, does modifying the contents of vector1 inside foo1, foo2 affect the original vector?

  4. And is vector1 automatically destroyed at the end of its scope, or do we have to delete it manually?
Foi útil?

Solução

Am I right to say that for foo1, the entire vector1 gets copied, and for foo2, only the reference to vector1 gets passed into the function?

Correct.

But isn't vector1, declared on the stack, supposed to be inaccessible anywhere else (i.e. from inside foo2) except the scope in which it was created?

It's just the name of vector1 that is not accessible outside, but you can freely pass its address around (passing it by reference or by pointer). Of course, it continues to exist as long as the function does not return, so returning a pointer to it would be an error (because it would point to a no longer existing object).

This differs from allocation on the heap, that has no scope-bound lifetime or automatic deletion - it's left to you. This is double-edged sword: you can have objects with custom lifetime, but you must remember do actually delete them when they are no longer needed.

Also, does modifying the contents of vector1 inside foo1, foo2 affect the original vector?

The argument to foo1 is a new, separated vector, any modification done to it will remain local to the function. The argument to foo2, instead, refers to vector1, so it will affect the original vector (actually, references are often described as "aliases" for other objects).

And is vector1 automatically destroyed at the end of its scope, or do we have to delete it manually?

It's automatically destroyed, as any local variable. But: vector2 will have to be deleted manually, since the local object is just the pointer, that has no destructor (by default it doesn't own the object it points to).

Outras dicas

If you want to pass a vector by reference, then you do it as shown in pseudocode for foo2().

vector<int> vector1 will allocate the vector, i.e. the header info, on the stack, but the elements on the free store ("heap").

vector<int> *vect = new vector<int>;

allocates everything on the free store.

vector<int*> vect;

will allocate the vector on the stack and a bunch of pointers on the free store.

Source: https://stackoverflow.com/a/8036528/2591612

As far as a copy passed to the function in foo1, the changes will remain local to the function. The vector is automatically destroyed at the end of its scope.

This code example should explain all the differences:

#include <vector>
#include <iostream>
#include <iterator>
#include <algorithm>

using namespace std;

void dumpVector(const vector<int>& v) {
    copy(begin(v), end(v), ostream_iterator<int>(cout, " "));
    cout << endl;
}

void foo1(vector<int> v) {
    cout << "I have been passed a copy of a vector. Modifications to my copy will not affect the original vector\n";
    for (auto& i : v) { i *= 2; }
    dumpVector(v);
}

void foo2(vector<int>& v) {
    cout << "I have been passed a reference to a mutable vector, which I will modify\n";
    for (auto& i : v) { i *= 2; }
    dumpVector(v);
}

void foo3(vector<int>* v) {
    cout << "I have been passed a pointer to a mutable vector, which I will modify\n";
    for (auto& i : *v) { i *= 2; }
    dumpVector(*v);
}

int main() {
    // this will be destructed automatically since it's on the stack
    vector<int> vector1 { 1, 2, 3 };

    // this will need an explicit delete
    vector<int>* vector2 = new vector<int> { 4, 5, 6 };

    foo1(vector1);
    foo2(vector1);
    foo3(&vector1);

    cout << "vector1 now contains ";
    dumpVector(vector1);

    foo1(*vector2);
    foo2(*vector2);
    foo3(vector2);
    cout << "*vector2 now contains ";
    dumpVector(*vector2);


    // always delete naked pointers. prefer the use of unique_ptr
    delete vector2;
};

output:

Compiling the source code....
$g++ -std=c++11 main.cpp -o demo -lm -pthread -lgmpxx -lgmp -lreadline 2>&1

Executing the program....
$demo 
I have been passed a copy of a vector. Modifications to my copy will not affect the original vector
2 4 6 
I have been passed a reference to a mutable vector, which I will modify
2 4 6 
I have been passed a pointer to a mutable vector, which I will modify
4 8 12 
vector1 now contains 4 8 12 
I have been passed a copy of a vector. Modifications to my copy will not affect the original vector
8 10 12 
I have been passed a reference to a mutable vector, which I will modify
8 10 12 
I have been passed a pointer to a mutable vector, which I will modify
16 20 24 
*vector2 now contains 16 20 24 
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top