3

假设我有两个容器存储指向相同对象的指针:

std::list<Foo*> fooList;
std::vector<Foo*> fooVec;

假设我通过以下方法从其中一个容器中删除一个对象:

std::vector<Foo*>::iterator itr = 
  std::find( fooVec.begin(), fooVec.end(), pToObj );
fooVec.erase( itr );

CppReference 说这调用了对象的析构函数。这是否意味着指向对象的指针fooList是一个悬空指针?

我不想使用引用计数指针。如何处理这个问题?

4

5 回答 5

6

不。

当您从容器中删除指针时,您所做的就是从容器中获取该指针值,没有任何内容被删除。(即:指针没有析构函数。)

但是,在容器中拥有事物的指针是很危险的。考虑:

std::vector<int*> v;
v.push_back(new int());
v.push_back(new int());
v.push_back(new int());

如果您从不检查容器并删除每个容器,那么您已经泄漏了。更糟糕的是它不是异常安全的。你应该使用一个指针容器,它会在它们被擦除时删除它指向的东西。(当容器破坏时,所有内容都会被删除。)

但是,在您的情况下,由于您在不同的地方共享一个指针,因此我看不到反对的论点shared_ptr; 这正是它的目的。

于 2010-07-24T18:12:16.797 回答
1

我认为不会调用对象的析构函数。中的指针fooList仍应指向有效数据。

如果您指的是这个链接,它是在谈论调用如何erase使您可能指向向量中后续位置的任何迭代器无效。但是使迭代器无效与调用delete向量中的某件事不同。

于 2010-07-24T18:12:11.477 回答
0

当你有一个指向对象的原始指针时,除非你删除它,否则不会调用析构函数。

您可以使用一种模式(或者它是一个习惯用法?)来确保您的对象在正确的时间被删除并且还使用指针容器(如许多算法中所需要的)是使用单独的双端队列来存储实际对象。您必须确保在任何指针容器之后销毁双端队列。您应该使用双端队列而不是向量的原因是您可以将对象添加到双端队列,而不会使指向先前存储的对象的指针无效。

于 2010-07-24T18:12:27.160 回答
0

两个容器都包含对 (Foo *) 对象的引用 - 因此,如果调用析构函数,它是指针对象的析构函数(可能什么都不做),而不是 Foo 对象本身的析构函数。原始对象(Foo 类)没有被破坏,因此没有悬空引用。

于 2010-07-24T18:14:06.913 回答
0

在您的情况下,存储在容器中的对象是原始指针的副本,而不是原始指针。因此,对于Foo*您决定存储的每个指针,您将拥有 3 个指针(原始指针、一个 infooList和一个 in fooVec),它们都指向内存中的同一位置。因此,当您调用erasedelete 时,将在指针本身而不是在它指向的内容上调用,并且指针上的 delete 是无操作的(它们没有像 GMan 所说的析构函数)。

于 2010-07-24T18:18:52.327 回答