1

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?
JeJo
  • 30,635
  • 6
  • 49
  • 88
  • What resources are you using to learn C++? Using `new` inside `display` makes no sense, and neither does the phrase "declare the `new` keyword". Any decent book or class should have told you about things like object life-time and about pointers, which would help you understand the issue here and why you have a leak. Perhaps you might need to invest in [some good books](https://stackoverflow.com/a/388282/440558)? – Some programmer dude Oct 19 '21 at 06:07
  • You're passing a `string` and an `int` to the constructor, and a `car*` to `display`, without declaring any of them first. – molbdnilo Oct 19 '21 at 06:16
  • 1
    Consider using automatic variables and also making `display()` a `car` member function. [example](https://godbolt.org/z/a9x8zKeWf) – Ted Lyngmo Oct 19 '21 at 06:26

2 Answers2

5

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++?

JeJo
  • 30,635
  • 6
  • 49
  • 88
0

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 memory 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));
}
Jason
  • 36,170
  • 5
  • 26
  • 60
  • As @Some Programmer dude said, there is no need of pointers/ smart pointers at all. BTW `std::make_shared` shouldn't be the first suggestion if you could `unique_ptr` and nothing to counte as reference. – Const Oct 19 '21 at 06:55
  • @Const Ofcourse the same program can be written in many different ways. For example, in this particular case OP could have created an object of type car inside main() and then pass that object(by reference or value as he/she chooses to) directly to `display()` instead of passing a pointer to the object. I corrected the mistake that he/she made in using/passing pointers. – Jason Oct 19 '21 at 07:08