关于c ++:从指针向量中删除东西

removing things from a pointer vector

我有一个这样的指针向量:

1
vector<Item*> items;

我想清除它。我试过了:

1
2
3
for (unsigned int i = 0; i < items.size(); i++)
    delete items.at(i);
items.clear();

1
2
3
4
5
while (!items.empty())
{
    delete items.back();
    items.pop_back();
}

1
2
3
4
5
while (!items.empty())
{
    delete items.at(0);
    items.erase(items.begin());
}

1
2
while (!items.empty())
    delete items.at(0);

其中每一个都会因为某种原因而爆炸,包括删除已经删除的对象和超出范围的向量迭代器。

我该怎么办?我希望能够重用相同的向量,并在稍后向其中添加更多的项指针。仅仅使用delete而不清除仍然会留下垃圾指针,对吗?

编辑:好的,我已经切换到共享模式了。现在我有

1
vector<shared_ptr<Item> > items;

然而,当我执行items.clear();时,我得到错误"向量迭代器不兼容"。我还在做错什么?


我用你删除东西的所有方法做了一个测试,其中一个根本不起作用。有关它们的注释,请参见下面的代码。

要回答您的问题"我该怎么做",下面是我在删除时的错误:1)确保内存是我的(我知道相应的新内存在哪里吗)?2)确保我没有删除内存(如果删除了,即使是我的内存,现在也不会删除)。3)如果您很确定您的SEG错误是由代码的单个部分引起的,那么在另一个项目中将其分解为一个小测试用例(类似于您在问题中所做的那样)。然后玩它。如果您在一个小项目中运行代码示例,那么您会在最后一个项目中看到SEG错误,并且会注意到在其他每种情况下都会进行删除。像这样分解代码会让您知道您需要跟踪如何将这些存储在向量中,以查看您在哪里失去了它们的所有权(通过删除,或将它们传递给删除它们的某个对象,等等)。

旁注:正如其他人所说,如果您可以使用智能指针,它们将为您处理内存管理。但是,请继续您的研究,并了解如何使用愚蠢的指针。有时您不能导入Boost,或者让qt为您进行内存管理。此外,有时您必须将指针存储在容器中,因此也不要害怕这样做(即:qt开发人员强烈建议使用指针来存储小部件,而不是引用或任何类似的内容)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#include <vector>

using namespace std;
class Item
{
public:
    int a;
};

int main()
{
    vector<Item *> data;

    for(int x = 0; x < 100; x++)
    {
        data.push_back(new Item());
    }

    //worked for me, and makes sense
    for(int x = 0; x < 100; x++)
    {
        delete data.at(x);
    }
    data.clear();

    for(int x = 0; x < 100; x++)
    {
        data.push_back(new Item());
    }
    //worked for me, and makes sense
    while (!data.empty())
    {
        delete data.back();
        data.pop_back();
    }
    data.clear();

    for(int x = 0; x < 100; x++)
    {
        data.push_back(new Item());
    }

    //  //worked for me, and makes sense
    while (!data.empty())
    {
        delete data.at(0);
        data.erase(data.begin());
    }

    for(int x = 0; x < 100; x++)
    {
        data.push_back(new Item());
    }

//  //This one fails, you are always trying to delete the 0th position in
//  //data while never removing an element (you are trying to delete deleted memory)
//  while (!data.empty())
//  {
//      delete data.at(0);
//  }


    return 0;
}

好吧,我做到了。经过一段时间,大量的阿司匹林和大量的脱发,我终于明白了问题所在。原来我之前调用了一个特殊的析构函数,这个析构函数包含了这个指针向量的类。我不知道仅仅调用析构函数会导致它擦除所有静态数据成员。我有时讨厌C++。


听起来好像向量中重复了相同的指针。为了确保只删除一次,只需将它们转移到std::set并删除它们。例如,

1
2
3
4
5
6
7
8
std::set<Item*> s( items.begin(), items.end() );
items.clear();

while ( !s.empty() )
{
    delete *s.begin();
    s.erase( s.begin() );
}

What do I do?

不要维护指针向量。实际上,这几乎总是一个错误,你正在与负责内存管理的向量(raii)的设计作斗争。现在您必须在每个指针上调用delete

你真的需要一个指针向量吗?如果您真的这样做了(不仅仅是认为您这样做了,而且它实际上是出于某种原因的需求),那么就使用智能指针。

向量会动态地为您分配内存,只需按照预期的方式使用它。


使用boost::shared_ptr,当向量被清除或元素被删除时,它们将被删除。


使用这样的智能指针向量:

1
vector<shared_ptr<Item> > myVect;

或者使用Boost中的指针容器库。

可能有一种方法可以做到这一点,并且可以重复使用,但是它似乎很容易出错,而且要做更多的工作,特别是考虑到Boost中的指针容器是一个只包含头的库。