这是一个人为的例子,说明了我遇到的问题。基本上,我创建了一个对象矢量,然后是一个指向对象的指针向量,然后打印指针和解除引用的对象。
#include <vector>
#include <iostream>
using namespace std;
namespace {
struct MyClass {
int* MyInt;
MyClass(int* i) : MyInt(i) {}
};
struct MyBigClass {
vector<MyClass> AllMyClassRecords; // Where I keep the MyClass instances
vector<int> TheInts;
void loadMyClasses();
void readMyClasses();
MyBigClass() {}
};
}
void MyBigClass::loadMyClasses() {
for (int i = 0; i < 10; ++i) {
TheInts.push_back(i); // Create an int
int *j = &TheInts[TheInts.size() - 1]; // Create a pointer to the new int
AllMyClassRecords.push_back(MyClass(j)); // Create a MyClass using pointer
}
}
void MyBigClass::readMyClasses() {
for (vector<MyClass>::iterator it = AllMyClassRecords.begin();
it != AllMyClassRecords.end(); ++it)
cout << it->MyInt << " => " << *(it->MyInt) << endl;
}
int main() {
MyBigClass MBC;
MBC.loadMyClasses();
MBC.readMyClasses();
}
基本上,我想创建一个指向另一个int向量的指针向量。问题是此代码打印出以下内容:
0x97ea008 => 159293472
0x97ea02c => 1
0x97ea040 => 2
0x97ea044 => 3
0x97ea078 => 4
0x97ea07c => 5
0x97ea080 => 6
0x97ea084 => 7
0x97ea0d8 => 8
0x97ea0dc => 9
它似乎按预期工作,除了第一个值,这可能是内存中的一些垃圾。为什么只有第一个值受到影响?如果我的代码被破坏了,为什么它只被插入第一个指针?
更新:我正在使用Ubuntu上的g++
进行编译。至于我正在做什么,我正在创建一个编译器分析通道。 MyClass
对象包含有关指令的信息,当我找到某些寄存器时,我想要更新这些指令。寄存器编号索引矢量矢量,因此特定寄存器编号将具有MyClass*s
的矢量。因此,如果找到寄存器,则向量中的任何MyClass
指针将用于更新单独的MyClass
向量中保存的MyClass
对象。因为我正在累积存储在MyClass
个对象中的指令信息和必须遵循MyClass
指针的寄存器信息,所以我无法创建整个MyClass
向量而不创建单独的传递,我想避免。
Update2:现在有图片......
Pass Progress inserts... InstRecs (TheInt) and updates... UpdatePtrs (MyClass)
---------------------- ------------------ -----------------------
| => I1: Uses r0, r1 | | InstRec for I1 | | r0: InstRec for I1* |
| I2: Uses r0, r2 | ------------------ | r1: InstRec for I1* |
---------------------- -----------------------
首先,pass传入一个InstRec,其中包含有关I1的信息。它还会创建指向由寄存器编号索引的新InstRec的指针。这里的r0实际上是一个指向IRe的InstRec的元素的向量,因此如果在后续指令中再次遇到r0,则会更新IRe的InstRec。
Pass Progress inserts... InstRecs (TheInt) and updates... UpdatePtrs (MyClass)
---------------------- ------------------ -----------------------
| I1: Uses r0, r1 | | InstRec for I1 | | r0: InstRec for I1* |
| => I2: Uses r0, r2 | | InstRec for I2 | | InstRec for I2* |
---------------------- ------------------ | r1: InstRec for I1* |
| r2: InstRec for I2* |
-----------------------
类似地,第二个条目将插入到InstRecs中,指针将添加到UpdatePtrs结构中。由于I2使用r0,因此另一个InstRec指针被推送到r0向量。未示出:当检测到I2使用r0时,传递在指针的r0向量的UpdatePtrs结构中查找,跟随每个指向其InstRec条目的指针,并用新信息更新InstRec。
希望这使我想要做的更清楚一些。我已经实现了@MerickOWA首先提出的使用InstRec向量索引而不是InstRec指针的建议(因为一旦将InstRecs添加到数组中,它们就永远不会移动),现在它似乎正在运行。
答案 0 :(得分:6)
你在做什么与创造这样的东西非常相似:
vector<int> MyInts;
vector< vector<int>::iterator > MyIntIters;
然后每次向MyInts
添加新的int时,都会得到迭代器并将迭代器推送到MyIntIters
。
您无法使用vector
执行此操作,因为只要向MyInts
添加新int,迭代器就会变为无效。
所以你的整个结构都被打破了。你需要提出一个全新的设计。首先,我问你为什么要一个迭代器(或指针)向量到另一个向量。是排序吗?索引以某种方式?别的什么?无论你想做什么,肯定有更好的方法。 您尝试做的将有助于确定如何来执行此操作。
阅读&amp;多次重读您的更新,在我看来,您正在尝试创建一个glom矢量。也就是说,一个可变长度的缓冲区,它在开头有结构化数据,后面有其他东西。
这是相当棘手的业务,需要动态分配。但是,您没有使用动态分配 - 您可以按值将对象推送到向量中。这些对象的指针会随着向量的大小调整而改变。
因此,如果这是你想要做的事情,你需要改变一些东西,以便使用new
创建你的glom,并将指针推到向量上的glom。这打开了整个潘多拉盒子的麻烦。你有多大的缓冲区?你怎么解决这个问题?你如何处理深拷贝,调整大小等?如何在不泄漏筛子的情况下正确释放胶体?正如我所说,棘手的业务。在我的工作中,我们一直在做这类事情,并且我们使用了一系列标准做法。这些需要付出很多努力。经过试验和试验的大量测试错误得到纠正,我们仍然发现问题。如果这就是你正在做的事情,你可能会考虑采取另一种方式。
答案 1 :(得分:4)
它不仅在第一个上被破坏,恰好是唯一被破坏的那个。如果你注意到,指针0到7指向不同的内存块,它们应该完全相邻。
std :: vector可以在向向量添加内容的任何时候重新分配动态对象所需的空间,并且它没有足够的容量。在添加或插入可能增加其大小的内容之后,您不能依赖指针(或迭代器)仍然有效。
有很多解决方案,比如
a)你可以提前预留空间(使用vector :: reserve),这样就不会发生这种动态重新分配,但是你必须知道你要添加的最大对象数。
b)等到所有对象都被添加,然后才能获得指向对象的指针
c)使用索引将对象和指向矢量的指针作为一对来引用您的对象直接与对象指针相对。它的工作量更大但不会改变(假设你没有在开头或中间插入/删除对象)
d)尝试检测向量何时重新分配其数据(vector :: capacity返回不同的值)并刷新指针向量并重建它
e)对于没有像std :: list这样的更改重新分配的对象使用不同的容器,并放弃对基础对象容器的随机访问,你仍然可以使用指针向量,但现在指针不会成为无效。 (你真的需要随机访问和指向对象吗?)f)重新考虑你的设计,不需要这样的指示
答案 2 :(得分:1)
您正在尝试存储指向矢量内容的指针。这不起作用,因为向量被设计为在内存中移动其内容以实现调整大小。
根据您的需要,您可能会:
将索引存储到向量中
发明了一些其他类型的“句柄”
更改向量以存储指向实例的智能指针(将使用“new”分配并单独存在),然后将另一个智能指针存储到同一实例。智能指针将保持引用计数,并在向量或外部代码不再引用实例时释放内存。 (当然,存在预先制定的解决方案:例如,请参阅boost::shared_ptr
。)
答案 3 :(得分:0)
push_back使迭代器和指针无效为向量。发生了什么:
上面的推入点1可以重新分配一个向量,并使先前采用前面元素的所有指针无效。他们指出的价值超出了你的控制范围。
为什么它只发生一次 - 只是运气(矢量可以分配比当前需要的更大的块)。
使用dequeue或list或预先保留所需的空间(如果你可以确定你需要多少)或者在完成添加之后得到指向第一个向量的指针(是的,它需要两个循环)。