I initialise the SmartPtr class with new Time(1,0,0)
.
//main.cpp
int main()
{
SmartPtr pTime0(new Time(0,0,1));
}
Nowhere am I calling delete on new Time(1,0,0)
. Everything works fine, the program complies and runs. but I am confused -- where should/should not I delete Time(1,0,0)
?
I do not understand the concept of temporary objects creating and deleting here.
I know whenever I write new
somewhere I MUST WRITE delete
!
Could someone please explain where delete Time(1,0,0)
takes place?
SmartPtr pTime0(new Time(0,0,1)) <-- new
here returns a pointer to a newly allocated memory, and then in ctor I allocate new
memory the second time??
//SmartPtr.cpp
SmartPtr::SmartPtr(Pointee * p):_pointee(new Pointee(*p))
{}
SmartPtr::~SmartPtr()
{
delete _pointee;
}
I don't know the details of your SmartPtr
class.
In any case, if you have a constructor like this:
SmartPtr::SmartPtr(Pointee * p):_pointee(new Pointee(*p)) {}
and this is the destructor:
SmartPtr::~SmartPtr() { delete _pointee; }
then with this code:
SmartPtr pTime0(new Time(0,0,1));
you leak one instance of Time(0,0,1)
.
In fact, you have one more new
than delete
(2 new
s and 1 delete
):
Step #1: You call new Time(0,0,1)
and create a new object on the heap.
(new
count == 1)
Step #2: You pass this pointer to SmartPtr
constructor, which deep copies previously created object and allocates a new copy on the heap, and keeps track of this copy via its _pointee
data member.
(new
count == 2)
Step #3: When the SmartPtr
destructor runs, it delete
s the instance pointed by _pointee
data member, but you leaked the firts Time(...)
created on the heap with new Time(0,0,1)
.
(delete
count == 1; new
count == 2)
A possible fix for that could be to just have this constructor:
SmartPtr::SmartPtr(Pointee * p)
: _pointee(p) // <--- transfer ownerhsip (no deep copies) !
{}
An easy way to identify potential leaks in these cases is to put some console tracing output in Time
class constructors and destructor, and check that the trace output of destructor matches the ones of constructors, e.g.:
Time::Time(....)
{
// Do construction work....
std::cout << "Time constructor\n";
}
Time::~Time(....)
{
// Do destructor work....
std::cout << "Time destructor\n";
}
The total count of "Time constructor"
strings should match the total count of "Time destructor"
strings.