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 new
ed should be delete
ed after wards(Manual memory management).
why didn't my user-defined destructor get called?
Because the object has not been delete
d 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));
}