EKP
EKP

Reputation: 95

I fail to use C++ pointer to point to the std::vector that is returned by a class method

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

Answers (3)

John Ilacqua
John Ilacqua

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

Not a real meerkat
Not a real meerkat

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

PaulMcKenzie
PaulMcKenzie

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

Related Questions