3

I have a class of the form

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

In some function, I pass an object of class A, say, obj, by reference

void func(A &o); //function declaration

and

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

However, I got the following error - double free or corruption (!prev)

According to the linked question, this is because the destructor is called multiple times for the pointer member, a consequence of the copy constructor being called multiple times when copying, causing an attempted deallocation of memory already deallocated. However, as I am passing the complete object by reference, why should this happen? Shouldn't the address of the whole object be simply copied?

Suggestions for implementing a copy constructor in the form given in the above link and here won't help as they involve allocating a fresh amount of memory whenever the object is copied, whereas I would like to pass the object, and as a result the pointer member, by reference.

I looked at this and this, potential duplicates,but they didn't solve my problem.

Based on a few other answers, I also tried implementing a destructor as

~A()
{
    delete[] a;
}

or

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

but neither solved the problem.

Community
  • 1
  • 1
GoodDeeds
  • 7,956
  • 5
  • 34
  • 61

2 Answers2

3

Try A(A const&)=delete; and A(A&&o):a(o.a){a=nullptr;}. This deletes your copy ctor and writes a non-allocating move ctor.

A deleted copy ctor will give you compile-time errors if you try to copy an instance of your class. As in your case this results in a crash at destruction, it seems like a good idea.

That move ctor will let you return instances of your class safely from functions, so long as the return value is implicitly or explicitly (std::move) moved-from.

Also consider

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;

Which lets you assign to A from another moved-from A.

The fact you should deal with move/copy assign/construct when you write a destructor is called the rule of five.

The fact you should avoid writing any of them is called the rule of zero.

To avoid writing them, replace your a with a unique_ptr<int[]>. Now it generates your move operations and destructor for you and deletes your copy operations, all automaticaly.

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524
1

I solved the problem. I had been returning an object of the class from a function, which invoked the copy constructor. I had overlooked the fact that the object would be passed by value.

The comment by @IgorTandetnik answers the question partly, to the extent that it confirmed that there was no reason for the problem I observed to happen except that I had overlooked a pass by value happening somewhere.

This answer from the link provided in @Slava's comment is highly useful for finding out the source of the problem.

Community
  • 1
  • 1
GoodDeeds
  • 7,956
  • 5
  • 34
  • 61