Reputation: 95
I tried to access the private vector member. I am curious why it did not work when I make the pointer point to the return vector (last case)
std::vector<double>* ptr3 = &(obj.GetVector());
std::cout << ptr3->at(0) << '\n'; //does not work
However, when I point to the newly created vector, it worked.
std::vector<double> vec3(obj.GetVector());
std::cout << vec3[3] << '\n'; //work. get 1.4
std::vector<double>* ptr1 = &vec3;
std::cout << ptr1->at(0) << '\n'; //work. get 1.1
The difference is just about skipping one line (assigned it to a vector first)
When the method directly return the pointer and I assigned it to another pointer, it also worked.
std::vector<double>* ptr2 = obj.GetVector2();
std::cout << ptr2->at(1) << '\n'; //work. get 1.2
Could you please teach/explain me on this behavior? Thank you.
The code of the cases discussed above is shown below.
#include <iostream>
#include <vector>
class AClass {
public:
AClass(): vec1({1.1,1.2,1.3,1.4}) {}
std::vector<double> GetVector() {
return vec1;
}
std::vector<double>* GetVector2() {
return &vec1;
}
private:
std::vector<double> vec1;
};
int main() {
AClass obj;
std::vector<double> vec2;
vec2 = obj.GetVector();
std::cout << vec2[2] << '\n'; //work. get 1.3
std::vector<double> vec3(obj.GetVector());
std::cout << vec3[3] << '\n'; //work. get 1.4
std::vector<double>* ptr1 = &vec3;
std::cout << ptr1->at(0) << '\n'; //work. get 1.1
std::vector<double>* ptr2 = obj.GetVector2();
std::cout << ptr2->at(1) << '\n'; //work. get 1.2
std::vector<double>* ptr3 = &(obj.GetVector());
std::cout << ptr3->at(0) << '\n'; //does not work
//get
//"Unhandled exception at 0x760FC54F in access_vector.exe"
//"exception: std::out_of_range at memory location 0x0033FA90
std::system("pause");
}
Upvotes: 0
Views: 66
Reputation: 977
AClass::GetVector()
returns a copy of the vector, so std::vector<double>* ptr3 = &(obj.GetVector());
calls that function, which creates a copy as a temporary, then takes the address of that temporary and stores it in ptr3
, after which the temporary is destroyed. So you have a dangling pointer - a pointer to an object that no longer exists.
Returning the pointer directly works because the pointer is directly to the data member, which still exists; and storing the copied vector into a local and then getting a pointer to it also works because, again, you're getting a pointer to an object with a lifetime at least as long as the pointer.
Upvotes: 1
Reputation: 5739
std::vector<double> GetVector() {
return vec1;
}
What's actually happening in the snippet above is that you are returning a copy of the vector.
Then you try to do this:
std::vector<double>* ptr3 = &(obj.GetVector());
Let's try to see what is happening here.
First, you get a copy of the vector:
obj.GetVector()
then, you get the address of the copy:
&(obj.GetVector())
This address is then assigned to ptr3
. The expression then ends, and the copy was never stored anywhere (remember, you just stored its address, instead of the object itself). Since it is a temporary, it is destroyed at the end of the expression.
Finally, you try to use the address you just got:
ptr3->at(0)
But since the object is destroyed, the address now points to garbage. This is why you're getting an error.
Upvotes: 1
Reputation: 35455
The issue is that AClass::GetVector()
returns a copy of the vector vec1
, not the actual vector vec1
declared in your AClass
class.
So this line:
std::vector<double>* ptr3 = &(obj.GetVector());
assigns the address of a temporary copy, which leads to undefined behavior if you use ptr3
after that line, since the copy is now gone.
One solution is to return a reference to the vector, and not a copy:
std::vector<double>& GetVector() {
return vec1;
}
The gist of this is that if you want to work with the original vector, return a reference to that vector, not a copy.
Upvotes: 2