繁体   English   中英

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

[英]Does using the assignment operator of the STL containers in my assignment operator leak memory?

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

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. 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. 对我来说,这意味着我的分配可以防止内存泄漏,但是以前我对文档进行了误解。 谢谢您的帮助。

代码看起来不错,但不要动态分配vector vector无论如何都会动态分配其元素,因此几乎没有使用分配容器本身的方法。 如果将vector设为数据成员,则代码将减少为:

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

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

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. 它试图实例化一个称为new的新向量; 这可能会引发异常,这会很好,完全没有问题
  3. 对操作符new的调用成功,但是所包含对象的分配器抛出异常; 您不会在构造函数中捕获异常,构造函数会抛出并且不会为您分配的(可能不是空的)向量调用任何析构函数->内存泄漏。

如果您使用的是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;}
}

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

在这种情况下,您从文档中引用的内容无关紧要,这意味着容器将使用相同的函数来分配其包含的对象。

就没有内存错误的意义而言,这看起来不错:您正在破坏时删除了向量(尽管没有必要先删除内容),并且实现了复制语义,以便每个向量完全由一个对象拥有。 该向量还具有正确的复制语义(否则可能会导致使用危险),因此您的赋值运算符是正确的。

但是,根本没有必要动态分配vector 为什么不使其成为成员变量? 然后,您可以将所有代码简化为以下内容:

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM