我无法使用C++指针指向类方法返回的 std::vector

  • 本文关键字:返回 类方法 std vector 指针 C++ c++
  • 更新时间 :
  • 英文 :


我试图访问私有向量成员。我很好奇为什么当我将指针指向返回向量时它不起作用(最后一种情况(

std::vector<double>* ptr3 = &(obj.GetVector());
std::cout << ptr3->at(0) << 'n'; //does not work

但是,当我指向新创建的矢量时,它起作用了。

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

你能教/解释一下我的这种行为吗?谢谢。

上面讨论的案例代码如下所示。

#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");
}

> 问题是AClass::GetVector()返回向量vec1的副本,而不是AClass类中声明的实际向量vec1

所以这行:

std::vector<double>* ptr3 = &(obj.GetVector());

分配临时副本的地址,如果在该行后使用ptr3,则会导致未定义的行为,因为该副本现已消失。


一种解决方案是返回对向量的引用,而不是副本:

std::vector<double>& GetVector() {
return vec1;
}

这样做的要点是,如果要使用原始向量,请返回对该向量的引用,而不是副本。

std::vector<double> GetVector() {
return vec1;
}

上面的代码片段中实际发生的事情是,您正在返回向量的副本

然后你尝试这样做:

std::vector<double>* ptr3 = &(obj.GetVector());

让我们试着看看这里发生了什么。

首先,您获得向量的副本:

obj.GetVector()

然后,您将获得副本的地址:

&(obj.GetVector())

然后将此地址分配给ptr3。然后表达式结束,副本永远不会存储在任何地方(请记住,您只是存储了它的地址,而不是对象本身(。由于它是临时的,因此在表达式的末尾被销毁。

最后,您尝试使用刚刚获得的地址:

ptr3->at(0)

但是由于对象被销毁,地址现在指向垃圾。这就是您收到错误的原因。

AClass::GetVector()返回向量的副本,因此std::vector<double>* ptr3 = &(obj.GetVector());调用该函数,该函数创建一个副本作为临时副本,然后获取该临时地址并将其存储在ptr3中,之后临时被销毁。所以你有一个悬空的指针 - 一个指向不再存在的对象的指针。

直接返回指针是有效的,因为指针直接指向仍然存在的数据成员;将复制的矢量存储到局部然后获取指向它的指针也是有效的,因为同样,你得到的指针指向一个对象的指针,其生存期至少与指针一样长。

最新更新