2

我从下面的代码中收到无效点错误,我不明白为什么。我要做的就是从向量中删除堆上的一些字符串:

void func() {
    vector<string>* vec = new vector<string>;
    vec->push_back(*(new string("1")));
    vec->push_back(*(new string("2")));

    for(vector<string>::iterator itr = vec->begin(); itr != vec->end(); ++itr)
    {
        string* ptr = &(*itr);
        delete(ptr);
    }
}

编辑:是因为 push_back 创建了字符串的副本吗?

4

3 回答 3

6

您的错误是因为该元素不是动态分配的;向量是。您尝试做的将需要:

void func() 
{
    vector<string*> vec;
    vec.push_back(new string("1"));
    vec.push_back(new string("2"));

    for(vector<string*>::iterator itr = vec.begin(); itr != vec.end(); ++itr)
    {
        string* ptr = *itr;
        delete(ptr);
    }
}

但老实说,我认为没有理由这样做。编写代码时,不仅会尝试删除它从未实际分配的内存,还会泄露它所做的分配。

有理由指向对象的指针存储在像这样的向量中(例如对象实际上来自其他地方的另一个容器,并且您需要一个临时列表来进行自定义排序操作​​而不干扰原始内容),但有些事情告诉我你离有这样的需求还有一段距离。

于 2013-02-22T19:33:32.917 回答
4

首先,线

vec->push_back(*(new string("1")));

导致内存泄漏。返回的值new string("1")是一个指向新分配的字符串对象的指针。但是,当您取消引用并将其插入向量中时,会创建并插入堆分配对象的副本。但是,您最初在堆上分配的实际字符串对象已泄漏。

本质上,您的向量是按值存储字符串对象,而不是指向字符串对象的指针。插入向量中的字符串对象的副本不是堆分配的对象(不是用 分配的对象new)。当然,你不能delete使用没有分配的东西new。所以当你打电话时,delete(ptr)你会导致未定义的行为。

您似乎想要的是:

vector<string*>* vec = new vector<string*>;

但是,总的来说,我看不出有任何令人信服的理由为什么要在堆上分配所有内容。在 C++ 中,只要可行,最好使用堆栈分配和具有值语义的容器,除非您有某些原因需要堆分配(例如,多态对象的容器,在这种情况下,无论如何您都应该使用智能指针)。通常,当新的 C++ 程序员到处使用堆分配对象和new关键字时,这表明他们无法很好地音译从 Java 或 C# 等托管语言导入的编程风格。

于 2013-02-22T19:34:46.373 回答
3

不,您不是-您的向量存储string对象,而不是指向string对象的指针。这就是为什么你*在你的push_back电话中有 - 你正在取消引用返回的指针。

您正在添加您创建的动态字符串的副本new,并且该动态字符串丢失了,因为您从不存储new返回的指针。

于 2013-02-22T19:33:10.870 回答