Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why delete is needed in the definition of the copy-assignment operator?

Tags:

c++

I am a C++ beginner. And I am doing the exercises in C++ Primer (5th Edition). I found a reference to Exercise 13.8 from Github (Here), which is shown below.

#include <string>
#include <iostream>

using std::cout;
using std::endl;

class HasPtr {
public:
    HasPtr(const std::string &s = std::string()) : ps(new std::string(s)), i(0) { }
    HasPtr(const HasPtr &hp) : ps(new std::string(*hp.ps)), i(hp.i) { }
    HasPtr& operator=(const HasPtr &hp) {
        std::string *new_ps = new std::string(*hp.ps);
        delete ps;          // I don't know why it is needed here? 
                            // But when I delete this line, it also works.
        ps = new_ps;
        i = hp.i;
        return *this;
    }

    void print() {
        cout << *(this->ps) << endl;
        cout << this->i << endl;
    }

private:
    std::string *ps;
    int i;
};

int main() {
    HasPtr hp1("hello"), hp2("world");
    hp1.print();
    hp1 = hp2;
    cout << "After the assignment:" << endl;
    hp1.print();
}

What makes me confusing is the HasPtr& operator=(const HasPtr &hp) function. I don't know why delete ps; is needed here. I thought it was an error, but it worked when I compiled the code. However, it also works when I delete the line of delete ps;. So, I do not know whether delete ps; is needed and what is the advantage if it is reserved.

like image 652
Wieshawn Avatar asked Dec 05 '22 19:12

Wieshawn


2 Answers

HasPtr::ps is an heap-allocated std::string pointer.

It is allocated and constructed using new in all HasPtr constructors. Therefore, when HasPtr::ps gets replaced by another heap-allocated pointer, the existing memory has to be released using delete to avoid memory leaks.

Note that, in modern C++, you should almost never use new and delete for managing objects like this. Use smart pointers instead, like std::unique_ptr or std::shared_ptr, which take care of memory management for you, safely and conveniently.

I still suggest getting familiar with new and delete, as an huge amount of existing code makes use of them. cppreference.com is a great place to find detailed information about the language.

As Jan Hudec mentioned in the comments, it is generally pretty silly to store an std::string on the heap - std::string is a wrapper around an heap-allocated character array, which already manages the memory for you.

like image 155
Vittorio Romeo Avatar answered Dec 08 '22 08:12

Vittorio Romeo


It's needed to prevent a memory leak: every new must be balanced with a delete.

You allocate memory for ps with a new in the constructors.

When you allocate memory for new_ps and assign this to ps, you need to free the constructor-allocated memory before you lose the old pointer value.

You program will indeed "work" if you omit that line, but it will steadily consume more and more memory, until, eventually there is no more memory left.

Note that you have another memory leak: you need to create a destructor, and call delete ps in it.

As you can see, this is getting unduly complicated. Better still, ditch all this pointer stuff and use a std::string s as the member variable - it takes care of all the memory management for you.

like image 38
Bathsheba Avatar answered Dec 08 '22 09:12

Bathsheba