在我的赋值操作符中使用STL容器的赋值运算符是否泄漏内存?

时间:2013-07-26 14:30:42

标签: c++ stl

我的一个类中有以下构造函数,析构函数和赋值运算符。我想知道它是否泄漏内存。

MenuItem::MenuItem() {
  menu_items = new vector<MenuItem>;
}

MenuItem::MenuItem(const MenuItem &other) {
  menu_items = new vector<MenuItem>(*other.menu_items);
}

MenuItem::~MenuItem() {
  menu_items->erase(menu_items->begin(), menu_items->end());
  delete menu_items;
}

MenuItem & MenuItem::operator= (const MenuItem &other) {
  *menu_items = *other.menu_items;
  return *this;
}

我主要担心的是赋值运算符。我查看了一些文档并发现了这一点:The container preserves its current allocator, which is used to allocate storage in case of reallocation. Any elements held in the container before the call are either assigned to or destroyed.对我而言,这意味着我的作业可以避免内存泄漏,但我之前错误地解释了文档。谢谢您的帮助。

3 个答案:

答案 0 :(得分:3)

代码看起来不错,但不动态分配vector。无论如何,vector动态分配其元素,因此很少使用分配容器本身。如果您将vector数据成员的代码缩减为:

struct MenuItem
{
  std::vector<MenuItem> menu_items;
};

其他所有内容都将由编译器隐式生成。如果您确实有new vector的正当理由,我建议的唯一更改是使用构造函数初始化程序列表进行初始化,而不是在析构函数中调用vector::erase,因为它是不必要的。 / p>

MenuItem::MenuItem() 
: menu_items(new vector<MenuItem>())
{}

MenuItem::MenuItem(const MenuItem &other)
: menu_items(new vector<MenuItem>(*other.menu_items))
{}

MenuItem::~MenuItem() 
{
  delete menu_items;
}

答案 1 :(得分:2)

由于赋值运算符,程序中没有内存泄漏。但是,在堆上分配向量感觉很奇怪,你有任何理由这样做吗?

实际上,如果包含的对象的分配器抛出异常,则可能存在内存泄漏。让我解释一下

  1. 您调用复制构造函数
  2. 它试图实例化一个调用new的新向量;这可能会抛出一个异常,这样就可以了,完全没问题
  3. 对运算符new的调用成功,但所包含对象的分配器抛出异常;你没有在构造函数中捕获异常,构造函数抛出并且没有调用析构函数 - &gt;内存泄漏,就像你分配的(可能不是空的)向量一样。
  4. 如果您使用的是C ++ 11,则可以通过从复制构造函数中委派默认构造函数来解决问题,如:

    MenuItem::MenuItem(const MenuItem &other) : MenuItem(){
      *menu_items = *other.menu_items;
    }
    

    如果你这样做,当你到达*menu_items的任务时,对象是完全构造的(通过: MenuItem(),那么说)如果这会抛出析构函数被调用,delete menu_items被执行。

    如果您不使用C ++ 11

    MenuItem::MenuItem(const MenuItem &other) : menu_items(NULL) {
      try{ menu_items = new vector<MenuItem>(*other.menu_items); }
      catch(...){delete menu_items;}
    }
    

    无论如何,这可能是一个更好的解决方案。

    您在文档中引用的内容与此上下文无关,它意味着容器将使用相同的函数来分配它包含的对象。

答案 2 :(得分:0)

在没有内存错误的意义上看起来很好:你在删除时删除了向量(尽管不需要先删除内容),并实现了复制语义,这样每个向量都只由一个对象拥有。该向量还具有正确的复制语义(否则将使用起来很危险),因此您的赋值运算符是正确的。

然而,动态分配vector毫无意义。为什么不把它变成一个成员变量呢?然后,您可以将所有代码简化为以下内容: