Home > Net >  Question about constructors & memory leak
Question about constructors & memory leak

Time:10-19

I was testing with constructors and destructors, and I want to see if I can pass an object to a function without declaring it first, like this example:

#include<iostream>
#include<stdlib.h>

using namespace std;

class car
{
public:
    string name;
    int num;

public:

    car(string a, int n)
    {
        cout << "Constructor called" << endl;
        this->name = a;
        this->num = n;
    }
    ~car()
    {
        cout << "Deleted" << endl;
    }
};

void display(car* p)
{
    cout << "Name: " << p->name << endl;
    cout << "Num: " << p->num << endl;
}

int main()
{
    display(new car("HYUNDAI", 2012));
}

The display function works fine, and it did exactly what I had expected, but I was wondering: if I had declared the new keyword inside the input to display, why didn't my user-defined destructor get called, and would that new cause a memory leak?

Thanks for your answer!

CodePudding user response:

Would that new cause a memory leak?

Yes, it is causing the memory leak. Whatever you newed should be deleteed after wards(Manual memory management).


why didn't my user-defined destructor get called?

Because the object has not been deleted and hence not been destructed.

You should be doing

void display(car* p)
{
    if (p) // check p is valid pointer
    {
        std::cout << "Name: " << p->name << std::endl;
        std::cout << "Num: " << p->num << std::endl;
        // ...after use
        delete p;
    }
}

Alternative to manual memory management, you could have used the smart pointers.

What is a smart pointer and when should I use one?


That being said, for the case shown, you do not need the pointers(unless you want to practice with the pointers). One option is to pass it as const car& which will work for temporary objects as well.

void display(const car& p)
//           ^^^^^^^^^^^^
{
    std::cout << "Name: " << p.name << std::endl;
    std::cout << "Num: " << p.num << std::endl;
     
}

and you can pass a car as

display(car{ "HYUNDAI", 2012 });

See: What are the differences between a pointer variable and a reference variable in C ?

CodePudding user response:

Yes there is a memory leak in your program because whenever you use new keyword to allocate some memory then you must always use delete to free up that memory later when no longer needed. Otherwise you will have a memory leak as in your program. There are 2 ways to solve your problem:

Solution 1: Use delete explicitly

int main()
{
    car * ptr = new car("HYUNDAI", 2012);
    display(ptr);
    
    //use delete to free up memory 
    delete ptr; //this will call the destructor
}

Solution 2: Use smart pointers

#include<iostream>
#include<stdlib.h>
#include <memory>
using namespace std;

class car
{
public:
    string name;
    int num;

public:

    car(string a, int n)
    {
        cout << "Constructor called" << endl;
        this->name = a;
        this->num = n;
    }
    ~car()
    {
        cout << "Deleted" << endl;
    }
};

void display(std::shared_ptr<car> p)
{
    cout << "Name: " << p->name << endl;
    cout << "Num: " << p->num << endl;
}

int main()
{
    std::shared_ptr<car> ptr = std::make_shared<car>("HYUNDAI", 2012);
    
    display(ptr);
    
    //there is no memory leak
    //you don't need to use delete explicitly
    
}

The advantage of using smart pointer(like shared_ptr or unique_ptr) is that you don't have to free them explicitly.

Using unique_ptr solution 2 looks like:

#include<iostream>
#include<stdlib.h>
#include <memory>
using namespace std;

class car
{
public:
    string name;
    int num;

public:

    car(string a, int n)
    {
        cout << "Constructor called" << endl;
        this->name = a;
        this->num = n;
    }
    ~car()
    {
        cout << "Deleted" << endl;
    }
};

void display(const std::unique_ptr<car> &p)
{
    cout << "Name: " << p->name << endl;
    cout << "Num: " << p->num << endl;
}

int main()
{
    unique_ptr<car> p1(new car("HYUNDAI", 2012));
    
    display(p1);
    
    //there is no memory leak
    //you don't need to use delete explicitly
    
}

Note that in your case you don't need to pass a pointer to display. You can instead pass the object directly as shown below:

#include<iostream>
#include<stdlib.h>

using namespace std;

class car
{
public:
    string name;
    int num;

public:

    car(string a, int n)
    {
        cout << "Constructor called" << endl;
        this->name = a;
        this->num = n;
    }
    ~car()
    {
        cout << "Deleted" << endl;
    }
};
//note pass by value(other way would be to use pass by reference like const car& p)
void display(car p)
{
    cout << "Name: " << p.name << endl;
    cout << "Num: " << p.num << endl;
}

int main()
{
    
    display(car("HYUNDAI", 2012));
}
  • Related