指向失去价值的对象向量的指针
Posted
技术标签:
【中文标题】指向失去价值的对象向量的指针【英文标题】:Pointer to vector of objects losing their value 【发布时间】:2019-05-21 19:17:06 【问题描述】:我正在为我的硕士论文开发一个项目。在这个项目中,我有一个名为 node 的父类和一些其他子类,例如 AND 类。我还有一个名为 graph 的类,其中节点使用 std::map 存储。我得出的结论是我不需要使用 std::map。使用 std::vector 我可以更快地访问图中的节点。
AND 类有两个向量:一个用于输入,另一个用于输出。我有两种方法可以将节点的指针添加到这两个向量之一。
当我在图形类中从 map 更改为 vector 时,AND 节点内的一些指针正在失去它们的值。
我对指针做了一些研究,在我看来我没有做错任何事。我迷路了。
class node
protected:
unsigned int id;
public:
virtual void pushOutput(node* param)
virtual void pushInput(node* param,bool param_polarity)
class AND : public node
vector <node*> inputs;
vector <node*> outputs;
public:
void pushOutput(node* param) override;
void pushInput(node* param,bool param_polarity) override;
void AND::pushOutput(node* param)
this->outputs.push_back(param);
//AND::pushInput is omitted, but it is pretty similar to AND::pushOutput except with a bunch of ifs.
class graph
protected:
// map<unsigned int,AND> all_ANDS;
vector<AND> all_ANDS;
public:
AND* pushAnd(unsigned int index,AND AND_obj);
AND* findAnd(unsigned int);
AND* graph::pushAnd(unsigned int index, AND AND_obj)
// std::pair<std::map<unsigned int,AND>::iterator,bool> ret;
// ret=this->all_ANDS.insert(pair<unsigned int,AND>(index,AND_obj));
all_ANDS.push_back(AND_obj);
return &all_ANDS.back();
AND* graph::findAnd(unsigned int param)
// return &this->all_ANDS.find(param)->second;
return &all_ANDS[param];
请注意注释行是代码用于正常工作的版本。
使用读取文件的方法(有些东西被省略了):
bool polar;
AND* AND_ptr;
unsigned int rhs0;
for(int l=0;l<A;l++)
and_index++;
AND AND_obj(and_index*2);
AND_ptr=this->pushAnd(and_index*2,AND_obj);
//reading info from file here and putting on rhs0 and polar.
AND_ptr->pushInput(findAnd(rhs0),polar);
findAnd(rhs0)->pushOutput(findAnd(and_index*2));
findAny(rhs0)->printNode();
如果我使用 graph::findAnd() 方法获取节点地址以将其推入另一个节点的向量:inputs 或 outputs 保存在这些向量上的地址指向一些垃圾,但只有在经过一段时间的处理后,它才会首先指向正确的位置,如 AND::printNode() 所示。
换句话说,graph::findAnd() 返回一个无效的指针,尽管使用 std::map 版本它工作得很好。
我很确定我的问题是由于缺乏指针知识。虽然当我检查类似Vector of object pointers returns odd values 的其他类似问题时。我的代码对我来说似乎没问题。
【问题讨论】:
请提供minimal reproducible example 得到一个good c++ book,看来你需要对内存管理有一些基本的了解 我对您的代码知之甚少,但可能的原因是std::vector
在您推送更多元素时需要重新分配,即指向元素的指针变得无效。 std::map
不是这种情况
推动矢量的有趣点。我认为它不会发生,因为它总是在向量的末尾。我还有其他选择吗?
【参考方案1】:
您必须考虑迭代器失效。来自cppreference 上std::vector::push_back
:
如果新的 size() 大于 capacity() 则所有迭代器和 引用(包括过去的迭代器)无效。 否则只有过去的迭代器无效。
这里的“引用”是在更广泛的意义上使用的,即指向元素的指针也会失效。原因是std::vector
保证将其数据保存在连续的内存块中,因此当您推送新元素时,之前的元素可能不得不移动。
我对您的代码了解太少,无法提供更多建议。请注意,std::list
在添加新元素时不会使迭代器无效(std::map
也是如此)。然而,这通常是不值得付出的代价(没有std::list
的数据本地化是杀手)。另一方面,如果容器的全部目的是启用引用元素而不使其失效,那么它可能是一个有效的选择。
【讨论】:
是的。这就是问题所在。我以为是我对指针的理解错了,但实际上是因为我在推回向量并搞砸了一切。我首先通过使用空白节点推回所需的节点数量而不是在读取文件时修改它们来解决。非常感谢您的关注!【参考方案2】:不要保留指向存储在vector
s 中的对象的指针。 vector
结构将其所有成员保存在连续的内存块中,因此当向量变大时可能需要分配一个新块,从而使所有指向 vector
中对象的指针无效。
我也强烈建议不要使用vector
的原始指针。这是一种不好的做法,它使得管理对象的生命周期变得非常困难,而这正是这里的错误。
例如,您可以对对象使用 vector
或 std::shared_ptr
s。然后您可以将额外的shared_ptr
s 存储到其他集合中的那些对象。
【讨论】:
对象在堆上分配。这些不是向量内部的指针,它们本身就是向量元素,因此重新分配不会以任何方式损害它们(只要这个特定的 STL 实现正确。)以上是关于指向失去价值的对象向量的指针的主要内容,如果未能解决你的问题,请参考以下文章