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

Rya*_*yan 0 c++ memory-management vector

我通过将它的内存分配给堆来创建了一个向量.然后我创建10个字符串对象也分配给堆内存并将它们存储在向量中.我试图使用delete运算符释放与每个新字符串对象关联的内存,但我不是如何做到的.我正在使用C++ 11.

#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;
}
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

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

Ide*_*Hat 5

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

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

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

可以解释为什么它只做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!
}
Run Code Online (Sandbox Code Playgroud)

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

  1. Vector已经在堆中分配了它的集合内存(除了指向内存和大小计数器的指针之外的所有内容).整个方法基于不了解这一事实.新的向量确实将整个向量放在堆中,这可能是OP想要的.
  2. 字符串也在堆中分配其内存.new std::string将简单地分配指向字符数组的指针和堆中的大小.所以这也值得注意.
  3. 如果你想要一个指针矢量,你应该有std::vector<T*>.std::vector<T>将是一个实例的向量T.
  4. 由于向量的内存已经在堆上分配,这最初似乎是徒劳的努力.但是,在某些情况下,您可能需要这样的结构.例如,必须以这种方式存储多态类型以避免切片.(但我会使用智能指针,但出于教育目的,这是一个很好的练习).
  5. 在循环1中,您动态分配一个字符串.然后,使用复制构造函数在向量中实例化实体实例.然后让指针超出范围.这是内存泄漏和低效副本.
  6. 您似乎真的想使用指针作为参考.std::string& s = *it比获取地址更具可读性.
  7. juanchopanza正确地指出你正在删除迭代器的位置,这是更未定义的行为.&it是类型的std::vector<string>::iterator*.为什么这可能不会崩溃和烧毁的是迭代器类型只包含内置类型,并且在此之后你没有做太多(你可能已经为自己设置了一些美味的堆栈损坏).如果你有一个std::vector<T*>(匹配的项目1)具有唯一所有权的向量,你想要这样做来清理它:

delete &(*it);

但做一些类似的东西会更好std::vector<std::unique_ptr<T>>,从不担心它.

  1. 从来没有使用全球使用标准.

  • @juanchopanza好点......发生的事情是更多的NASAL DEAMONS. (2认同)