为啥我指向向量第一个元素的指针会丢失?
Posted
技术标签:
【中文标题】为啥我指向向量第一个元素的指针会丢失?【英文标题】:Why does my pointer to the first element of a vector get lost?为什么我指向向量第一个元素的指针会丢失? 【发布时间】:2019-10-17 08:13:05 【问题描述】:#include <iostream>
#include <vector>
//#include <string>
struct Point
Point(int _x, int _y)
x = _x;
y = _y;
int x;
int y;
Point *parent;
;
int main()
Point start(3, 4);
std::vector<Point> points;
points.push_back(start);
std::cout << points.back().x << "," << points.back().y << "\n";
Point one(4, 5);
one.parent = &points.at(0);
//std::cout << "testing: " << one.parent->x << "," << one.parent->y << "\n";
points.push_back(one);
std::cout << "One: " << points[1].x << "," << points[1].y << "\n";
std::cout << "One's parents: " << points[1].parent->x << "," << points[1].parent->y << "\n";
Point two(10, 3);
two.parent = &points.back();
points.push_back(two);
std::cout << "Two: " << points[2].x << "," << points[2].y << "\n";
std::cout << "Two's parent: " << points[2].parent->x << "," << points[2].parent->y << "\n";
Point three(12, 7);
three.parent = &points[1];
points.push_back(three);
std::cout << "Three: " << points[3].x << "," << points[3].y << "\n";
std::cout << "Three's parents: " << points[3].parent->x << "," << points[3].parent->y << "\n";
return 1;
我得到以下结果: 3,4 一:4,5 父母:0,0 二:10,3 两人的父母:4,5 三:12,7 三人的父母:4,5
即使我将一个父点指向向量的第一个元素,该值最终还是 0,0。但是,其他指针指向我想要的元素。
【问题讨论】:
一旦你这样做了points.push_back(one);
std::vector
被允许重新分配保存所有数据的整个数组,所以这意味着如果你之前存储了指针,例如:&points.back()
,它可能不再是有效。
注意:如果您需要扩展代码,可以扩展此问题的更安全的解决方案是将vector
设为std::vector<std::shared_ptr<Point>>
,并让parent
成为Point
的成员也是std::shared_ptr<Point>
(假设它是DAG;如果它可以有循环,则需要std::weak_ptr<Point>
,并且管理变得更加困难)。这避免了Point
s 和存储它们的vector
之间的紧密耦合(其中parent
仅在有效的全局vector
的上下文中才有意义)。
明智地使用std::make_shared
(这既更安全,又允许直接std::shared_ptr
无法做到的性能优化),它不会增加太多开销,而且可以让你解放相当多。
【参考方案1】:
std::vector
有一个capacity
。如果添加超出向量当前容量的元素,vector 可能会决定分配一个更大的块,移动现有元素,然后添加新元素。你的情况一定也发生过这种情况。
您可以使用reserve
提升现有向量的容量。这还不会添加额外的元素;它只是准备向量。
【讨论】:
要明确:它可能会为额外元素的原始实例结构消耗内存(肯定是虚拟地址空间,实际 RAM 占用的数量非常依赖于实现),因此对于std::vector<Point>
在 OP 的情况下,调用 reserve
通常会保留 12-16 字节的内存(取决于指针宽度)乘以保留大小。它不必初始化内存,对于实例间接在堆上存储昂贵属性的类,该成本不会立即支付,但它必须保留原始内部数组。【参考方案2】:
虽然 MSalters 正确解释了问题的原因,以及针对这种特殊情况的可能解决方案,但一般做法有点不同。因为vector
可能随时重新分配,所以存储指向其元素的指针通常是个坏主意。
您可以改用索引,无论重新分配如何,它都是有效的;或者你可以考虑使用不同的数据结构,比如std::list
。
std::list
的元素在其整个生命周期中都保持在同一位置。
【讨论】:
注意:如果您知道vector
的最终或最大大小,只要有问题的元素,适当的reserve
调用可以确保有效指针保持有效没有移动/更换。我不会说存储指向 vector
元素的指针总是是一个坏主意,只是如果你不能将 reserve
/resize
vector
一次存储到它永远不会超过的大小。
@ShadowRanger 你是对的。但是这样做你必须 100% 确定将来没有人愿意在 vector
中添加更多元素,比如在初始开发后的 5 年或 10 年。当产品需求可能演变成完全不同的东西时。
@Jurlie:好的设计是将该向量封装在一个类中,并具有明确定义的外部接口。如果产品需求发生变化,则可以考虑该类是否可以按原样使用、需要更新还是需要重写。以上是关于为啥我指向向量第一个元素的指针会丢失?的主要内容,如果未能解决你的问题,请参考以下文章