2

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

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.对我来说,这意味着我的作业不会发生内存泄漏,但我之前误解了文档。谢谢您的帮助。

4

3 回答 3

3

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

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

其他所有内容都将由编译器隐式生成。如果您确实有正当理由使用,我建议newvector唯一更改是使用构造函数初始化程序列表进行初始化,而不是调用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;
}
于 2013-07-26T14:43:52.080 回答
2

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

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

  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;}
}

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

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

于 2013-07-26T14:36:07.073 回答
0

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

但是,动态分配完全没有意义vector。为什么不让它成为一个成员变量呢?然后,您可以将所有代码简化为以下内容:

于 2013-07-26T14:35:06.340 回答