首页 文章

释放分配给存储在向量内的堆的内存

提问于
浏览
0

我已经通过分配它创建了一个向量's memory to the heap. I then create 10 string objects also allocated to heap memory and store them inside the vector. I' ve试图释放与每个新字符串对象相关联的内存,使用 delete 运算符,但是我使用C 11来使用'm not how to do it. I' m .

#include <vector>
#include <string>
#include <iostream>

using namespace std;

int main()
{
   vector<string> *v = new vector<string>;

   for(int i = 0; i < 10; i++) {
     // allocate a new string object on the heap
     string *a = new string("Hello World");
     //de-reference the string object
     v->push_back(*a);
   }

  // show the contents of the vector
  for(auto i = v->begin(); i != v->end(); ++i) {
    // okay so this makes a lot more sense than:
    // const string &s = *i;
    // this way we create a pointer to a string object
    // it is a lot more clear this way
    const string *s = &(*i);
    cout << *s << " " << s->length() << endl;
  }

  cout << endl << endl;

  for(vector<string>::iterator it = v->begin(); it != v->end(); ++it) {
    delete &it;
    v->erase(it);
  }

  for(auto i = v->begin(); i != v->end(); ++i) {
   cout << *i << endl;
  }
  cout << endl << "Size: " << v->size() << endl;

  delete v;
}

g++ -std=c++11 main.cc -o main

我的错误是并非所有对象都被删除 . 我最后在最后4个语句后留下了5个对象 . 一旦完成这些操作,我希望向量内部有零个对象 .

我的输出:

Hello World 11
Hello World 11
Hello World 11
Hello World 11
Hello World 11
Hello World 11
Hello World 11
Hello World 11
Hello World 11
Hello World 11


Hello World
Hello World
Hello World
Hello World
Hello World
Size: 5

问题是并非所有对象都被删除 .

4 回答

  • 5

    我认为你在无数问题中担心的特殊问题是你的for循环不是删除所有项目,即:

    for(vector<string>::iterator it = v->begin(); it != v->end(); ++it) {
      delete &it;
      v->erase(it);
    }
    

    您的问题是您正在更改正在迭代的向量,这会导致未定义的行为,因为您没有删除所有值 . (只要不添加或删除值,向量的迭代器才有效) .

    我可以解释为什么它只做5,但答案不是跨平台的 . 在这种情况下,编译器可以随意做任何事情 . 对于编译器来说,让恶魔飞出你的鼻子也同样有效 .

    基本上,你正在删除一个值,然后他们移动到下一个索引 . 所以你在0处删除了什么,它会将1处的值拉到0处 . 然后你移动到索引1,它包含以前在索引2中的内容 . 然后你删除它 . 基本上,您从向量中删除所有偶数索引 .

    编辑:将问题减少到最小可重复性:

    std::vector<int> vals;
    
    for (int i = 0; i < 11; i++0) vals.push_back(i);
    
    for (std::vector<int>::iterator i = vals.begin(); i != vals.end(); ++i)
    {
       vals.erase(i);//after this point, i's behavior is undefined!
    }
    

    编辑3:使用代码枚举所有问题(基于Meta对话的建议操作)

    • Vector已经在堆中分配了它的集合内存(除了指向内存和大小计数器的指针之外的所有内容) . 整个方法基于不了解这一事实 . 新的向量确实将整个向量放在堆中,这可能是OP想要的 .

    • string也可以在堆中分配内存 . new std::string 将简单地将指针分配给字符数组和堆中的大小 . 所以这也值得注意 .

    • 如果你想要一个指针矢量,你应该有 std::vector<T*> . std::vector<T> 将是 T 实例的向量 .

    • 由于向量的内存已经在堆上分配,这最初看起来似乎是徒劳的努力 . However, there ARE instances where you MAY want such a structure. 例如,必须以这种方式存储多态类型以避免切片 . (但我会使用智能指针,但出于教育目的,这是一个很好的练习) .

    • 在循环1中,您动态分配一个字符串 . 然后,使用复制构造函数在向量中实例化实体实例 . 然后让指针超出范围 . 这是内存泄漏和低效副本 .

    • 您似乎真的想使用指针作为引用 . std::string& s = *it 比获取地址更具可读性 .

    • juanchopanza正确地指出你正在删除迭代器的位置,这是更加未定义的行为 . &it 的类型为 std::vector<string>::iterator* . 为什么这可能不会崩溃和烧毁是因为迭代器类型只包含内置类型,而且你可能会为自己的堆栈损坏做好准备 . 如果您有一个 std::vector<T*> (匹配项目1),该矢量具有唯一所有权,您需要这样做以清理它:

    delete &(*it);

    但是做一些像_577652这样的事情会好得多,而且从不担心它 .

    • 永远不要使用全局使用标准 .
  • 1

    问题是并非所有对象都被删除 .

    这是因为在填充向量时,您正在泄漏字符串 .

    for(int i = 0; i < 10; i++) {
      string *a = new string("Hello World"); // Leak: who deletes a? Nobody!
      v->push_back(*a);
    }
    

    这将是一种避免特定泄漏的方法:

    for(int i = 0; i < 10; i++) {
      v->push_back("Hello World");
    }
    

    你仍在动态分配 v ,没有理由这样做 . 在C语言中,这将是一种更简单,更惯用的方法 . 与您的版本不同,它不涉及内存泄漏或未定义的行为:

    int main()
    {
       vector<string> v(10, "Hello World");
    
       for (auto& s : v)
         cout << s.length() << endl;
    }
    

    你不需要拨打 new . 您无需担心内存管理问题 .

  • 0

    当您使用v-> push_back(* a)时,您正在向量上推送字符串的副本;命令 . 如果你不想这样做,你需要让你的向量成为字符串指针的向量,然后将指针自身推到向量上 .

  • 2

    我不明白你为什么要动态分配字符串,即使你是按值存储它 . 这个片段即使是教育目的也没有意义,除非你学习如何在C中泄漏内存 .

    for(int i = 0; i < 10; i++) {
         // allocate a new string object on the heap
         string *a = new string("Hello World");
         //de-reference the string object
         v->push_back(*a);
       }
    

    如果你想在任何stl容器中存储指针,那么我建议使用一些智能指针(EXCLUDING AUTO_PTR),如boost :: shared_ptr . 他们为您处理内存管理 .

相关问题