【问题标题】:Pointers not actually pointing to objects themselves?指针实际上并不指向对象本身?
【发布时间】:2011-08-21 01:44:30
【问题描述】:

我目前有一个类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

和

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

为什么vector&lt;Foo *&gt; 中指向c 的指针在b 在vector&lt;Foo&gt; 中被删除后不会一直指向c?有什么办法可以补救吗?

(我知道如果我删除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 *>
}

【问题讨论】:

  • 请提供填充数组的代码,这是必不可少的部分。
  • 让我戴上我的通灵帽。

标签: c++ pointers vector


【解决方案1】:

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

如果您有一个 vector 包含元素 a, b, c, d 并删除元素 b,则元素 c 和 d 在数组中向下移动一个索引以填充由已删除元素创建的孔,留下包含a, c, d 的数组。

指针在移动时不会“跟随”vector 中的元素。如果您有一个“指向c”的指针,那么该指针确实指向“数组中索引2 处的元素”。当您从数组中删除b 时,“索引2 处的元素”然后是d,而不是c。

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

【讨论】:

  • 哦,我明白了。我忘记了指针只是指向内存位置而不是跟随实际对象本身。
  • @Tomalak:嗯,我的精神力量并不是特别可靠。不过,我喜欢有机会尝试使用它们。 :-)
  • 请记住,从 std::vector 中删除元素可能会导致它被重新分配,从而使指向其中元素的所有指针无效。
  • @Novelocrat:擦除永远不会导致重新分配。
  • 或者,@wrongusername 可以切换到 std::list。从列表中删除元素不会移动以下元素。
【解决方案2】:

如果你想完成这样的事情,你将无法使用vector&lt;foo&gt; 来实际负责foo 对象本身。在我看来,您的foo* 的子向量必须实际上指向vector&lt;foo&gt; 负责的内存。 (因此,这就是为什么您仍然会在末尾看到指向 d 的附加指针,而您的长度仍然为 4。)

在我看来,您真正想要做的是使用两个vector&lt;foo*&gt;,并手动创建第一个存储的对象,而不是让向量本身负责对象。然后让您的第二个vector&lt;foo*&gt; 简单地将指针复制到您创建的对象。这样,当您从第一个 vector&lt;foo*&gt; 中删除项目时,它只会删除其指针副本,而您的第二个 vector&lt;foo*&gt; 将不受影响。

考虑一下不涉及向量:

// 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];。但它可以让您拥有似乎是您想要的行为。

【讨论】:

    【解决方案3】:

    当vector 中的对象被删除时,vector 中较大索引处的所有对象都将向下移动以关闭“洞”。指向这些对象中的任何一个的指针都变得无效。检测这种情况的唯一方法是首先不要进入那种情况——不要将指向非constvectors 中的对象的指针存储起来,因为这很危险。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-02-09
      • 1970-01-01
      • 2011-09-15
      • 1970-01-01
      • 2018-05-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多