当包含指针成员的类对象通过引用传递时,为什么析构函数被多次调用?我如何更正此问题?

时间:2017-01-14 05:14:17

标签: c++ pointers memory reference destructor

我有一个表格

class A
{
    int **a;
    //other members  
}

在某些函数中,我通过引用

传递A类的对象,比如obj
void func(A &o); //function declaration

func(std::ref(obj)); //function call

但是,我收到以下错误 - double free or corruption (!prev)

根据链接的问题,这是因为析构函数被多次调用指针成员,这是复制构造函数在复制时被多次调用的结果,导致尝试释放已经解除分配的内存。但是,当我通过引用传递完整的对象时,为什么会发生这种情况呢?不应该简单地复制整个对象的地址吗?

以上述链接和here中给出的形式实现复制构造函数的建议无济于事,因为它们涉及在复制对象时分配新的内存量,而我想传递对象,作为结果指针成员,通过引用。

我查看了thisthis,可能重复,但他们没有解决我的问题。

基于其他一些答案,我也尝试将析构函数实现为

~A()
{
    delete[] a;
}

~A()
{
    if(a)
    {
        delete[] a;
    }
}

但都没有解决问题。

2 个答案:

答案 0 :(得分:2)

尝试A(A const&)=delete;A(A&&o):a(o.a){a=nullptr;}。这将删除您的副本ctor并写入一个非分配移动ctor。

如果您尝试复制类的实例,则删除的副本ctor将为您提供编译时错误。在你的情况下,这会导致破坏时崩溃,这似乎是一个好主意。

移动ctor将允许您从函数中安全地返回类的实例,只要返回值是隐式或显式(std::move)移动的。

还要考虑

A& operator=(A&&o) { 
  if (this==&o) return *this; 
  std::swap(a,o.a); 
  delete[] o.a; 
  o.a=nullptr; 
  return *this; 
}
A& operator=(A const&o)=delete;

可让您从另一个移动的A分配给A

当你编写析构函数时,你应该处理移动/复制赋值/构造的事实被称为五的规则。

你应该避免写任何一个这个事实被称为零规则。

为避免编写它们,请将a替换为unique_ptr<int[]>。现在它为您生成移动操作和析构函数,并自动删除您的复制操作。

答案 1 :(得分:0)

我解决了这个问题。我从一个函数返回了该类的对象,该函数调用了复制构造函数。我忽略了这个对象将按值传递的事实。

@IgorTandetnik的评论在一定程度上回答了这个问题,只要它确认我没有理由发现这个问题,除非我忽略了某个地方发生的价值传递。

answer评论中提供的链接中的@Slava's对于找出问题的根源非常有用。