2011-08-21 58 views
0

我目前有一个类的向量Foo和另一个向量指针指向载体Foo的一个子集。我目前有一个函数,用于从vector<Foo *>中选择一些指针,并从实际包含它们的vector<Foo>中删除它们。因此,在一开始,两个向量是这样的:指针实际上并不指向对象本身?

//Foo classes in vector<Foo> 
a 
b 
c 
d 

//Foo pointers in vector<Foo *> 
*a 
*b 
*c 
*d 

然而,我发现,删除Foo后,说b,他们是这样的:

//Foo classes in vector<Foo> 
a 
c 
d 

and

//Foo pointers in vector<Foo *> 
*a 
*c 
*d 
*d 

如何在vector<Foo *>中指向c的指针不会指向c之后bvector<Foo>中被删除?有什么方法可以补救吗?

(我明白,如果我删除b,原来指针b将是一个晃来晃去,但是因为我没有打算访问其删除后b无论如何,我认为这不会有问题,我可以去与指针c)下一个索引

编辑:

按照要求,在指针向量被填充的代码:

for(int i = 0; i < a.size(); i++) //a is the vector<Foo> 
{ 
    Foo * thisFoo = &a[i]; 
    if(someConditionMet) 
     b.push_back(thisFoo); //b is the vector<Foo *> 
} 
+0

请提供填充阵列的代码,那是必要的部分。 –

+0

让我戴上我的心灵帽。 –

回答

3

A vector将其元素存储在数组中。数组是连续的元素序列。

如果你有含vector元件a, b, c, d和除去元件b,然后元件cd在阵列以填充由去除的元件所产生的孔中向下移动一个索引,含有离去a, c, d阵列。

指针在移动时不会“跟随”vector中的元素。如果您有一个指向“c”的指针,该指针实际上指向“数组中索引为2的元素”。当您从阵列中删除b时,“index 2处的元素”为d,而不是c

如果您希望某个对象具有永不改变的固定地址,您应该自己动态分配它并使用智能指针(如unique_ptrshared_ptr)跟踪它。

+0

哦,我明白了。我忘记了指针只是指向内存位置,而不是跟随实际的对象本身。 – wrongusername

+0

@Tomalak:恩,我的心理能力不是特别可靠。不过,我喜欢尝试使用它们的机会。 :-) –

+2

请记住,从std :: vector中移除一个元素可能会导致它被重新分配,使所有指向它的元素的指针无效。 – Novelocrat

1

vector中的对象被移除时,vector中较大索引处的所有对象向下移动以关闭“孔”。指向任何这些对象的指针都会失效。检测情况的唯一方法不是首先考虑这种情况 - 不要在非constvector s中存储指向对象的指针,因为它很危险。

2

如果你想完成这样的事情,你将不能使用vector<foo>实际上自己负责foo对象。它看起来像我的foo*的子矢量必须实际上指向vector<foo>负责的内存。 (因此,这就是为什么你仍然看到指向d的末尾的额外指针,而你仍然有4的长度。)

对我来说,你真正想要做的是使用两个vector<foo*>'s,并手动创建存储在第一个中的对象,而不是让矢量本身负责对象。然后让你的第二个vector<foo*>只是复制指针到你创建的对象。这样,当你从第一个vector<foo*>中删除一个项目时,它只会删除它的指针副本,而你的第二个vector<foo*>将不受影响。

认为它没有向量涉及:

// create the initial storage for all the foo 
foo* fooarray = new foo[foo_count]; 

// create all the foos for the array 
for (int i=0; i < foo_count; ++i) 
    fooarray = new foo(); 

// get a pointer to a subset of foo 
foo* foo_subset_pointer = &fooarray[10]; 

// make a list of a subset of the fooarray pointers 
foo* foo_subset_list = new foo[10]; 
for (int i=0; i < 10; ++i) 
    foo_subset_list = fooarray[i]; 

所以,现在当你从fooarray删除元素:

// remove fooarray[3] 
delete fooarray[3]; 
for (int i=4; i < 20; ++i) 
    fooarray[i-1] = fooarray[i]; 

foo_subset_pointer将有原来的第3项删除,因为它是只是一个指向现有数组的指针。 (如果你访问foo_subset_pointer[19],它仍然有一个指向同样的事情foo_subset_pointer[18],因为项目未归零......)

但糟糕的是,foo_subset_list[3]仍然指向原来的位置:但它是无效的,因为它被删除了!这就是为什么当你处理一个你想要保留的子集时,你不想让这个向量负责你的列表项目。

相反,它听起来像你希望你的第一个向量只能删除该项目(上面的for循环),而不是delete。在这种情况下,它将保持您的foo_subset_list[3]不变,仍然指向有效的foo。另外的困难是你现在必须确保在将来某个时候做delete foo_subset_list[3];。但它可以让你拥有似乎是你想要的行为。