Reputation: 913
I was looking to understand how vector
is implemented in C++. There was a previous question that asked this, and so I took a look at it, and I have a small question. Assuming the implementation in the linked question is correct, let's look at this code:
int main(){
Vector<int> test2 = test_Vector();
cout << test2[0] << endl;
return 0;
}
// below is NOT the STL vector object, but the one in the linked question,
// in which the asker tries to implement STL vector himself/herself
Vector<int> test_Vector(){
Vector<int> test;
test.push_back(5);
return test;
}
As I understand it, the test
Vector
object is created locally, so when the test_Vector
method returns, the local object goes out of scope, thereby calling the destructor and delete
-ing the dynamic array. Since the code actually works and 5 is printed, I guess I'm wrong. What's the right explanation?
Upvotes: 3
Views: 2064
Reputation: 63481
You are right, but you're missing one important thing.
Because you're returning a Vector<int>
, you should think of it as being copied. This would normally invoke the copy constructor, which copies test
into a new instance of Vector<int>
. The copy constructor is implemented in the linked question as:
template<class T>
Vector<T>::Vector(const Vector<T> & v)
{
my_size = v.my_size;
my_capacity = v.my_capacity;
buffer = new T[my_size];
for (int i = 0; i < my_size; i++)
buffer[i] = v.buffer[i];
}
Note that the copy constructor might not be invoked due to Return Value Optimization (see hair-splitting in comments below). Compilers are allowed to optimize the copy away in many cases, and the C++ standard allows for the fact that this optimization may change program behaviour.
Whether the object is copied, or RVO is applied, you should end up with the same thing. The optimization should not ruin your object provided you follow normal object-oriented practices.
You should always think of function return values being passed by value (ie copied) regardless of type, and then consider that your compiler is probably doing RVO. It's important not to forget the Rule of Three (or Four, or Five).
Upvotes: 3
Reputation: 2556
When test
is returned its copy constructor is invoked (in theory) which allocates a new chunk of memory and copies the contents of test
. The original test
on test_Vector
s stack is destructed (in theory) and test2
gets assigned the copy, which means the assignment operator will be invoked (in theory) which will again allocate memory and copy the data from the temporary object that was created when returning. The temporary object returned from test_Vector
then has its destructor called (in theory).
As you can see, without compiler optimizations this is hell :) The "in theory"s can be skipped if you don't do anything too baroque and the compiler is smart and your situation is this simple. See this for some updates to the story as of C++11.
Upvotes: 1
Reputation: 46359
He provided a public copy constructor (technically, he didn't make the copy constructor private), so the standard C++ logic kicks in and makes a copy of the object to return. The new object is local to main
. Inside the copy constructor, new memory is malloc
ed and the data copied over. If he hadn't provided a copy constructor, it would have accessed invalid memory (trying to access the memory from the pointer which has been freed)
Upvotes: 1