【问题标题】:Where am I getting wrong in the destructor for this C++ container?我在这个 C++ 容器的析构函数中哪里出错了?
【发布时间】:2013-09-04 03:10:52
【问题描述】:

我正在处理一个map,它的第二个元素也是map,它的第二个元素是vector。在地图构建过程中,似乎我必须动态分配内存,但后来我无法正确释放内存。我的问题可以归结为下面的源码。

我就是不明白为什么析构函数不正确。

另外,有没有更好的方法来避免这种情况下的内存泄漏?

#include <vector>
#include <map>
#include <iostream>

using namespace std;

typedef vector<int> IntVect;
typedef map<int, IntVect> NumEle;
typedef map<int, NumEle> Nums;

class NumLess {
 public:
  Nums numSet;
  ~NumLess() {
    for (Nums::iterator I = numSet.begin(), E = numSet.end(); I != E; ++I) {
      NumEle &numEle = I->second;
      for (NumEle::iterator II = numEle.begin(), EE = numEle.end(); II != EE; ++II) {
        IntVect &intVect = II->second;
        intVect.clear();
        delete &intVect;
      }
      delete &numEle;
    }
  }
  friend ostream &operator<<(ostream &os, const NumLess &numLess) {
    for (Nums::const_iterator I = numLess.numSet.begin(),
                              E = numLess.numSet.end();
         I != E; ++I) {
      const NumEle &numEle = I->second;
      os << "NumEle:" << I->first << endl;
      for (NumEle::const_iterator II = numEle.begin(), EE = numEle.end();
           II != EE; ++II) {
        os << "IntVect  " << II->first << " | ";
        const IntVect &intVect = II->second;
        for (auto i : intVect) {
          os << i << " ";
        }
        os << endl;
      }
    }
    return os;
  }
};

int main(void) {
  NumLess numLess;
  for (unsigned h = 4; h > 0; --h) {
    NumEle *numEle = new NumEle();
    for (unsigned i = h; i > 0; --i) {
      IntVect *intVect = new IntVect();
      for (unsigned j = 0; j < i; ++j) {
        intVect->push_back(j);
      }
      numEle->insert(pair<int, IntVect>(i, *intVect));
    }
    numLess.numSet.insert(pair<int, NumEle>(h, *numEle));
  }
  cout << numLess;
  cout << "finished" << endl;
  return 0;
}

【问题讨论】:

  • Don't use new 你已经大大降低了内存泄漏的几率。
  • @chris 但我只是不知道正确的数据结构以避免使用new

标签: c++ memory-management memory-leaks stl destructor


【解决方案1】:

长话短说:您正在删除未分配的对象。要修复它,您需要从析构函数中删除删除。

您的主电源也有泄漏。您正在堆上创建对象,并且永远不会释放。创建的对象被复制到容器中。要修复此泄漏,请移除新对象,然后将对象添加到容器中。


如果您更喜欢使用指针(我认为不好),您需要更改您的 typedef:

typedef map<int, IntVect*> NumEle;
typedef map<int, NumEle*> Nums;

这里是 'main()' 没有 'new' 和内存泄漏:

int main(void) {
  NumLess numLess;
  for (unsigned h = 4; h > 0; --h) {
    NumEle numEle;
    for (unsigned i = h; i > 0; --i) {
      IntVect intVect;
      for (unsigned j = 0; j < i; ++j) {
        intVect.push_back(j);
      }
      numEle.insert(pair<int, IntVect>(i, intVect));
    }
    numLess.numSet.insert(pair<int, NumEle>(h, numEle));
  }
  cout << numLess;
  cout << "finished" << endl;
  return 0;
}

【讨论】:

  • 但我想我是在使用析构函数间接释放内存。
  • @HongxuChen 只需删除代码中带有“new”和“delete”的行,看看如何修复您的程序。你的析构函数不需要做任何事情。 Contrainer 的析构函数会做需要做的事情。
  • 我只是发现如果没有new,我很难让代码运行起来。比如numEle会在循环结束后销毁(Am I right?),而在实际代码中,我必须使用numLess.numSet以备将来使用。
  • 但是我们能保证在这个初始化之后,分配的不会被释放,这样numLess的数据信息如果传递给函数可以在其他函数中使用吗?会不会是分配的空间被意外释放了?
  • @HongxuChen 意外发布是什么意思?当然,它会工作得很好
猜你喜欢
  • 1970-01-01
  • 2021-02-11
  • 2011-07-21
  • 1970-01-01
  • 2013-02-06
  • 2013-01-06
  • 1970-01-01
  • 1970-01-01
  • 2016-08-02
相关资源
最近更新 更多