1

I am reading the C++ Programming Language 4th Edition and I reached the section regarding Copy Assignment Constructors. The author has a class named Vector and he defines the copy assignment constructor like this

Vector& Vector::operator=(const Vector& a)
{
   double* p = new double[a.sz];
   for (int i=0; i != a.sz; ++i)
      p[i] = a.elem[i];
   delete[] elem;
   elem = p;
   sz = a.sz;
   return *this
}

(For those who own the book, this can be found in page 74) Now, my question is: if p has a new resource, why isn't it released with a delete before the return? or said in another way: Why isn't the lack of a delete[] p considered a memory leak?

I ask this because, so far, I've noticed that for every new there must be a delete and the questions I've seen that say "Should I use delete here" state that for every new, there should be a delete. I saw this question Must new always be followed by delete? but in that case, the program finishes and the resource is released, while in the above code the program continues.

(Also, on a side question, would the elem = p statement call the copy-assignment constructor? this line confuses me because it seems like it would call it and do a sort of infinite loop)

Community
  • 1
  • 1
Compa
  • 190
  • 1
  • 11
  • You don't see the delete in there? Sixth line? – Benjamin Lindley Feb 03 '16 at 05:28
  • 3
    Well, the “matching” `delete[] p` is actually in `Vector::~Vector`. – 5gon12eder Feb 03 '16 at 05:30
  • Benjamin Lindley, the delete in the sixth line is (I believe) to release the memory that the array had before the actual assignment. The way I see it is like saying x=2, what happened to the previous value of x? it was "deleted" (not in the literal sense) since elem is a pointer, you have to make sure it is empty before assigning something else to it. – Compa Feb 03 '16 at 05:39
  • 1
    @Compa: Right, and the next time you call the assignment operator, the delete statement in that call releases the memory that was allocated in *this* call. And this repeats each time you call the assignment operator, releasing the memory allocated by the previous call, until the destructor is called. – Benjamin Lindley Feb 03 '16 at 05:43

4 Answers4

2

The general pattern is that if a class holds a resource, then its destructor will release the resource (see RAII). So, undoubtedly, there is something like

Vector::~Vector()
{
    delete[] elem;
}

elsewhere.

At various points of the object's lifetime, other operations might release the resource, e.g., the copy assignment constructor in this case. If this is done, then either the resource will be carefully reallocated, or it will be set to a state indicating that there is nothing to release (by setting it to nullptr, for example).


Regarding your second question. The copy assignment operator of Vector is simply assigning a new value to a pointer - there is no recursion involved.

Ami Tavory
  • 66,807
  • 9
  • 114
  • 153
  • Actually, there is. I didn't understand the relation until I read Tas answer, specifically the part where he says "he memory that p is pointing to is also pointed to by elem" – Compa Feb 03 '16 at 05:45
2

For each new that gets executed, there should be a delete somewhere that gets executed. It should not necessarily be in the same function. Moreover, one occurrence of delete in the text of the program may match several different occurrences of new and vice versa. Execution counts must match, not textual occurrences.

elem = p doesn't call anything. elem and p are pointers. It's a built-in type assignment.

n. 'pronouns' m.
  • 95,181
  • 13
  • 111
  • 206
1

The delete you are worried about will be done in destructor of this case.

What is code is doing is create space for data, copies the data and free the old memory. Leaving the new memory to be handled later, RAII

For the side note:

 elem = p

It will not invoke copy operation of the class as they are pointer to POD, plain old data type

dlmeetei
  • 7,297
  • 3
  • 25
  • 34
1

You're right about p being allocated with no subsequent call to delete[]; however, as you've also observed, the memory that p is pointing to is also pointed to by elem:

double* p = new double[a.sz]; // allocate memory
delete[] elem; // delete the old memory
elem = p; // point to the new memory allocated

As others have pointed out, elem gets deleted in the destructor.

There is no copy constructor call, because there is no copying: the pointer elem is just changing where it points to.

Tas
  • 6,589
  • 3
  • 31
  • 47