I'm currently trying to learn about classes and constructors/destructors. I understand what the two do, but I'm having a harder time with the destructors because I can't think of a practical application for its use.
Can anyone provide an example with an explanation?
Destructors are special member functions used to release any resources allocated by the object.
The most common example is when the constructor of the class uses new, and the destructor uses delete to deallocate the memory.
class Myclass
{
int *m_ptr;
public:
Myclass():m_ptr(new int)
{
}
~Myclass()
{
delete m_ptr;
}
//ToDo: Follow Rule of Three
//Provide definitions for copy constructor & copy assignment operator as well
};
Destructors are probably the most important aspect of c++, it manages resources for you and allows you add code to handle any special cleanup such as handle deallocation, disconnections from sockets, DB's etc.. Bjarne Stroustup also states that this is one of the nice things about destructors:
There have also been positive surprises. The most spectacular has been
the pervasive use of destructors in techniques relating to resource
management and error handling (using exceptions). I knew destructors
were a good idea—after all, you have to reverse the effect of a
constructor—but I didn't realize quite how central they would be to
good use of C++.
Original article: http://msdn.microsoft.com/en-us/magazine/cc500572.aspx
It is also essential to the idiom RAII (Resource Acquisition Is Initialisation) and explained by Bjarne in this article:
http://www.artima.com/intv/modern3.html
You can read this C++ faq on destructors which should help you even more.
I think Als code sample is a fine example, you can also look at the code sample in the wikipedia article which is also another example. The fact that the destructor is called when the object goes out of scope or when delete is called is very useful. Something I use is a timer object class to time how long certain function calls take:
class myTimer
{
mytimer():startTime( TimeNow() )
{}
~myTimer()
{
printf("time taken :%I64d", TimeNow() - startTime);
}
private:
__int64 startTime;
};
so in my code I would do something like this
myClass::myFunction()
{
myTimer timer; // initiliases time to Now.
someOtherFunc();
} // mytimer object is now out of scope and the destructor is called and prints the time it took
Imagine you have a class for file operations, e.g. ifstream and you like that this file is closed automaticly the instance of the class go away. Put a close on the file handle in the desctructor.
these have the most power when you have composition of dynamically allocated objects
say that I am making linkedList structure that holds pointers to linkedListNodes the list will hold the pointers to the first, and depending on singly, or doubly the last element.
in the destructor I would place the removal of all elements in the list, and therefore the list itself.
If I do not code the destructor then when the list goes out of scope, or has delete called on it the memory that was allocated for those elements is lost, and cannot be reclaimed by the system (most notably called a memory leak)
Constructors and Destructors are very important pieces of the RAII (Resource Allocation Is Initialization) idiom. Linking the acquisition of resources (files, memory, sockets, other class objects) to the lifetime of an object is a very powerful tool. When an object goes out of scope, either through normal execution or due to an exception, having the object destructor called allows the class to clean up its resources properly, without having to burden the code using an object with lots of extra finalization steps.
Extending #Als's answer here, for example you have a class,
class A {
B* ptrB; // B is another class / struct / internal type
A() { ptrB = new B(); }
}
int main() {
A* ptrA = new A();
// Do something with A
delete ptrA; // This does not free ptrA->ptrB
}
To take care of this problem, declare a destructor in A as follows,
~A() { delete ptrB; } // This is called every time delete is called on
// an object of A
Related
I have started to C++ and need some clarifications regarding memory management in C++. I have come across smart pointers, but I wish to understand some basic concepts.
Here's a sample structure
struct A
{
private:
int a;
void* b;
public:
A(int i, void* m) { a=i; b=m; }
};
main()
{
A * a1 = new A(10, 0);
//
//Some Code
if(on some condition) {
delete a1;
a1=nullptr;
}
}
When I delete a1, will m also be deleted automatically or should i explicitly delete m before deleting a1 as given below?
delete a1->b;
a1->b = nullptr;
delete a1;
a1=nullptr;
When I delete a1, will m also be deleted automatically
No, it won't (your code probably has a memory leak). You need an explicit destructor deleting it.
BTW, using a void*b; pointer field is poor taste. You should prefer some more explicit type (e.g. double*b; or SomeClass* b;) if you know it. This makes your code more readable, and give more opportunities for helpful type checking at compile time.
// inside struct A
~A() { delete b; };
Read about the rule of five.
Notice that struct-s are very similar to class-es in C++.
Avoid memory leaks. Tools like valgrind could be helpful. And using systematically smart pointers and standard containers should help to avoid them. If your field b was declared std::shared_ptr<std::string> b; the default destructor would have freed it appropriately. And perhaps you want it to be some std::vector<std::string> (again, the default destructor is releasing memory appropriately).
A good coding hint is to avoid, when possible, declaring raw pointers (prefer smart pointers and containers). When you have to declare one, you need to code its delete appropriately.
Welcome to C++, a very powerful language that requires you to take responsibility of the details to achieve the flexibility that allows such power. If you like, you can make it very complex, however for most constructs their is an easy way as well.
First of all, you ain't required to release memory, if your program exits, it will clean it. However, as you don't call delete, the Dtor will not be called which might cause specific code to not be executed.
So in general, it's good practice to clean up the allocated memory.
If you don't need the heap, don't use it
new A(10, 0) will allocate memory on the heap. If you don't want that, this can as well be created on the stack. Which causes auto cleanup: A a{10, nullptr};
Use RAII
As soon as you decide, you need heap allocated memory, you should default to std::unique_ptr. Which changes the code to: auto a = std::make_unique<A>(10, nullptr); With this, ownership is within the unique_ptr, which can be moved around (std::move). If you don't want to transfer ownership, you can dereference it or call the method get.
Applying these 2 practices, including for members, will prevent a lot of memory leaks and will reduce the time you need to think about it.
Don't use void*
void* is evil, don't use it unless you have to (and you only have to when interfacing with C). There are many ways of avoiding it. The best one is introducing an interface.
class I {
public:
virtual ~I() = default;
};
class M : public I
{
// ...
};
class A
{
// ...
std::unique_ptr<I> m;
// ...
};
Need something special?
Some times, you need something special in the Dtor, only in that case you should implement the Dtor explicitly. Given your question, I'm gonna assume you are a beginner and as such don't need to know about more details for now.
This question already has answers here:
What is The Rule of Three?
(8 answers)
Closed 8 years ago.
I read that destructors need to be defined when we have pointer members and when we define a base class, but I am not sure if I completely understand. One of the things I am not sure about is whether or not defining a default constructor is useless or not, since we are always given a default constructor by default. Also, I am not sure if we need to define default constructor to implement the RAII principle (do we just need to put resource allocation in a constructor and not define any destructor?).
class A
{
public:
~Account()
{
delete [] brandname;
delete b;
//do we need to define it?
};
something(){} =0; //virtual function (reason #1: base class)
private:
char *brandname; //c-style string, which is a pointer member (reason #2: has a pointer member)
B* b; //instance of class B, which is a pointer member (reason #2)
vector<B*> vec; //what about this?
}
class B: public A
{
public something()
{
cout << "nothing" << endl;
}
//in all other cases we don't need to define the destructor, nor declare it?
}
The rule of Three and The Rule of Zero
The good ol' way of handling resources was with the Rule of Three (now Rule of Five due to move semantic), but recently another rule is taking over: the Rule of Zero.
The idea, but you should really read the article, is that resource management should be left to other specific classes.
On this regard the standard library provides a nice set of tools like: std::vector, std::string, std::unique_ptr and std::shared_ptr, effectively removing the need for custom destructors, move/copy constructors, move/copy assignment and default constructors.
How to apply it to your code
In your code you have a lot of different resources, and this makes for a great example.
The string
If you notice brandname is effectively a "dynamic string", the standard library not only saves you from C-style string, but automatically manages the memory of the string with std::string.
The dynamically allocated B
The second resource appears to be a dynamically allocated B. If you are dynamically allocating for other reasons other than "I want an optional member" you should definitely use std::unique_ptr that will take care of the resource (deallocating when appropriate) automatically. On the other hand, if you want it to be an optional member you can use std::optional instead.
The collection of Bs
The last resource is just an array of Bs. That is easily managed with an std::vector. The standard library allows you to choose from a variety of different containers for your different needs; Just to mention some of them: std::deque, std::list and std::array.
Conclusion
To add all the suggestions up, you would end up with:
class A {
private:
std::string brandname;
std::unique_ptr<B> b;
std::vector<B> vec;
public:
virtual void something(){} = 0;
};
Which is both safe and readable.
As #nonsensickle points out, the questions is too broad... so I'm gonna try to tackle it with everything I know...
The first reason to re define the destructor would be in The Rule of Three which is on part the item 6 in Scott Meyers Effective C++ but not entirely. The rule of three says that if you re defined the destructor, copy constructor, or copy assignment operations then that means you should rewrite all three of them. The reason is that if you had to rewrite your own version for one, then the compiler defaults will no longer be valid for the rest.
Another example would be the one pointed out by Scott Meyers in Effective C++
When you try to delete a derived class object through a base class pointer and the base class has a non virtual destructor, the results are undefined.
And then he continues
If a class does not contain any virtual functions, that is often an indication that it is not meant to be used as a base class. When a class is not intended to be used as a base class, making the destructor virtual is usually a bad idea.
His conclusion on destructors for virtual is
The bottom line is that gratuitously declaring all destructors virtual is just as wrong as never declaring them virtual. In fact, many people summarize the situation this way: declare a virtual destructor in a class if and only if that class contains at least one virtual function.
And if it is not a Rule Of three case, then maybe you have a pointer member inside your object, and maybe you allocated memory to it inside your object, then, you need to manage that memory in the destructor, this is item 6 on his book
Be sure to check out #Jefffrey's answer on the Rule of Zero
There are precisely two things that necessitate defining a destructor:
When your object gets destructed, you need to perform some action other than destructing all class members.
The vast majority of these actions once was freeing memory, with the RAII principle, these actions have moved into the destructors of the RAII containers, which the compiler takes care of calling. But these actions can be anything, like closing a file, or writing some data to a log, or ... . If you strictly follow the RAII principle, you will write RAII containers for all these other actions, so that only RAII containers have destructors defined.
When you need to destruct objects through a base class pointer.
When you need to do this, you must define the destructor to be virtual within the base class. Otherwise, your derived destructors won't get called, independent of whether they are defined or not, and whether they are virtual or not. Here is an example:
#include <iostream>
class Foo {
public:
~Foo() {
std::cerr << "Foo::~Foo()\n";
};
};
class Bar : public Foo {
public:
~Bar() {
std::cerr << "Bar::~Bar()\n";
};
};
int main() {
Foo* bar = new Bar();
delete bar;
}
This program only prints Foo::~Foo(), the destructor of Bar is not called. There is no warning or error message. Only partially destructed objects, with all the consequences. So make sure you spot this condition yourself when it arises (or make a point to add virtual ~Foo() = default; to each and every nonderived class you define.
If none of these two conditions are met, you don't need to define a destructor, the default constructor will suffice.
Now to your example code:
When your member is a pointer to something (either as a pointer or a reference), the compiler does not know ...
... whether there are other pointers to this object.
... whether the pointer points to one object, or to an array.
Hence, the compiler can't deduce whether, or how to destruct whatever the pointer points to. So the default destructor never destructs anything behind a pointer.
This applies both to brandname and to b. Consequently, you need a destructor, because you need to do the deallocation yourself. Alternatively, you can use RAII containers for them (std::string, and a smart pointer variant).
This reasoning does not apply to vec because this variable directly includes a std::vector<> within the objects. Consequently, the compiler knows that vec must be destructed, which in turn will destruct all its elements (it's a RAII container, after all).
If you dynamically allocate memory, and you want this memory to be deallocated only when the object itself is "terminated", then you need to have a destructor.
The object can be "terminated" in two ways:
If it was statically allocated, then it is "terminated" implicitly (by the compiler).
If it was dynamically allocated, then it is "terminated" explicitly (by calling delete).
When "terminated" explicitly using a pointer of a base-class type, the destructor has to be virtual.
We know that if a destructor is not provided, the compiler will generate one.
This means that anything beyond simple cleanup, such as primitive types, will require a destructor.
In many cases, dynamic allocation or resource acquisition during construction, has a clean up phase. For example, dynamically allocated memory may need to be deleted.
If the class represents a hardware element, the element may need to be turned off, or placed into a safe state.
Containers may need to delete all of their elements.
In summary, if the class acquires resources or requires specialized cleanup (let's say in a determined order), there should be destructor.
I was reading an article that stated due to something called RAII, you no longer needed to cleanup your code.
What prompted this research was I am currently coding something that requires cleanup before exiting the function.
For example, I have created a file, and mapped a view of a file.
Normally, I'd just use goto or do {break;} while(false); to exit. However, is it true this is no longer necessary with C++11?
I.e. no more
if( fail ) {
UnmapViewOfFile(lpMapView);
CloseHandle(hFileMap);
CloseHandle(hFile);
}
every few lines of code?
Does the compiler automatically wrap this up once the function exits? It just seems hard to believe that it actually cleans up function calls like the article said it did. (I may have misinterpreted it somehow.) What seems more likely is that it just cleans up created class libraries by calling their deconstructor from the C++ library.
EDIT: The article - from Wikipedia:
It doesn't necessarily state that it cleans up these function calls, but it does imply it does for C++ library function objects (such as FILE * , fopen, etc objects)
Does it work for WinAPI too?
C++ standard surely says nothing about usage of windows API functions like UnmapViewOfFile or CloseHandle. RAII is a programming idiom, you can use it or not, and its a lot older than C++11.
One of the reasons why RAII is recomended is that it makes life easier when working with exceptions. Destructors will always safely release any resources - mostly memory, but also handles. For memory your have classes in standard library, like unique_ptr and shared_ptr, but also vector and lots of other. For handles like those from WinAPI, you must write your own, like:
class handle_ptr {
public:
handle_ptr() {
// aquire handle
}
~handle_ptr() {
// release
}
}
Cleanup is still necessary, but due to the possibility of exceptions the code should not do cleanup simply by executing cleanup operations at the end of a function. That end may never be reached! Instead,
Do cleanup in destructors.
In C++11 it is particularly easy to any kind of cleanup in a destructor without defining a custom class, since it's now much easier to define a scope guard class. Scope guards were invented by Petru Marginean, who with Andrei Alexandrescu published an article about it in DDJ. But that original C++03 implementation was pretty complex.
In C++11, a bare bones scope guard class:
class Scope_guard
: public Non_copyable
{
private:
function<void()> f_;
public:
void cancel() { f_ = []{}; }
~Scope_guard()
{ f_(); }
Scope_guard( function<void()> f )
: f_( move( f ) )
{}
};
where Non_copyable provides move assignment and move construction, as well as default construction, but makes copy assignment and copy construction private.
Now right after successfully acquiring some resource you can declare a Scope_guard object that will guaranteed clean up at the end of the scope, even in the face of exceptions or other early returns, like
Scope_guard unmapping( [&](){ UnmapViewOfFile(lpMapView); } );
Addendum:
I should better also mention the standard library smart pointers shared_ptr and unique_ptr, which take care of pointer ownership, calling a deleter when the number of owners goes to 0. As the names imply they implement respectively shared and unique ownership. Both of them can take a custom deleter as argument, but only shared_ptr supports calling the custom deleter with the original pointer value when the smart pointer is copied/moved to base class pointer.
Also, I should better also mention the standard library container classes such as in particular vector, which provides a dynamic size copyable array, with automatic memory management, and string, which provides much the same for the particular case of array of char uses to represent a string. These classes free you from having to deal directly with new and delete, and get those details right.
So in summary,
use standard library and/or 3rd party containers when you can,
otherwise use standard library and/or 3rd party smart pointers,
and if even that doesn't cut it for your cleanup needs, define custom classes that do cleanup in their destructors.
As #zero928 said in the comment, RAII is a way of thinking. There is no magic that cleans up instances for you.
With RAII, you can use the object lifecycle of a wrapper to regulate the lifecycle of legacy types such as you describe. The shared_ptr<> template coupled with an explicit "free" function can be used as such a wrapper.
As far as I know C++11 won't care of cleanup unless you use elements which would do. For example you could put this cleaning code into the destructor of a class and create an instance of it by creating a smart-pointer. Smart-pointers delete themselves when they are not longer used or shared. If you make a unique-pointer and this gets deleted, because it runs out of scope then it automatically calls delete itself, hence your destructor is called and you don't need to delete/destroy/clean by yourself.
See http://www.cplusplus.com/reference/memory/unique_ptr/
This is just what C++11 has new for automatically cleaning. Of course an usual class instance running out of scope calls its destructor, too.
No!
RAII is not about leaving clean-up aside, but doing it automatically. The clean-up can be done in a destructor call.
A pattern could be:
void f() {
ResourceHandler handler(make_resource());
...
}
Where the ResourceHandler is destructed (and does the clean-up) at the end of the scope or if an exception is thrown.
The WIN32 API is a C API - you still have to do your own clean up. However nothing stops you from writing C++ RAII wrappers for the WIN32 API.
Example without RAII:
void foo
{
HANDLE h = CreateFile(_T("C:\\File.txt"), FILE_READ_DATA, FILE_SHARE_READ,
NULL, OPEN_ALWAYS, 0, NULL);
if ( h != INVALID_HANDLE_VALUE )
{
CloseHandle(h);
}
}
And with RAII:
class smart_handle
{
public:
explicit smart_handle(HANDLE h) : m_H(h) {}
~smart_handle() { if (h != INVALID_HANDLE_VALUE) CloseHandle(m_H); }
private:
HANDLE m_H;
// this is a basic example, could be implemented much more elegantly! (Maybe a template param for "valid" handle values since sometimes 0 or -1 / INVALID_HANDLE_VALUE is used, implement proper copying/moving etc or use std::unique_ptr/std::shared_ptr with a custom deleter as mentioned in the comments below).
};
void foo
{
smart_handle h(CreateFile(_T("C:\\File.txt"), FILE_READ_DATA, FILE_SHARE_READ,
NULL, OPEN_ALWAYS, 0, NULL));
// Destructor of smart_handle class would call CloseHandle if h was not NULL
}
RAII can be used in C++98 or C++11.
I really liked the explanation of RAII in The C++ Programming Language, Fourth Edition
Specifically, sections 3.2.1.2, 5.2 and 13.3 explain how it works for managing leaks in the general context, but also the role of RAII in properly structuring your code with exceptions.
The two main reasons for using RAII are:
Reducing the use of naked pointers that are prone to causing leaks.
Reducing leaks in the cases of exception handling.
RAII works on the concept that each constructor should secure one and only one resource. Destructors are guaranteed to be called if a constructor completes successfully (ie. in the case of stack unwinding due to an exception being thrown). Therefore, if you have 3 types of resources to acquire, you should have one class per type of resource (class A, B, C) and a fourth aggregate type (class D) that acquires the other 3 resources (via A, B & C's constructors) in D's constructor initialization list.
So, if resource 1 (class A) succeeded in being acquired, but 2 (class B) failed and threw, resource 3 (class C) would not be called. Because resource 1 (class A)'s constructor had completed, it's destructor is guaranteed to be called. However, none of the other destructors (B, C or D) will be called.
It does NOT cleanup `FILE*.
If you open a file, you must close it. I think you may have misread the article slightly.
For example:
class RAII
{
private:
char* SomeResource;
public:
RAII() : SomeResource(new char[1024]) {} //allocated 1024 bytes.
~RAII() {delete[] SomeResource;} //cleaned up allocation.
RAII(const RAII& other) = delete;
RAII(RAII&& other) = delete;
RAII& operator = (RAII &other) = delete;
};
The reason it is an RAII class is because all resources are allocated in the constructor or allocator functions. The same resource is automatically cleaned up when the class is destroyed because the destructor does that.
So creating an instance:
void NewInstance()
{
RAII instance; //creates an instance of RAII which allocates 1024 bytes on the heap.
} //instance is destroyed as soon as this function exists and thus the allocation is cleaned up
//automatically by the instance destructor.
See the following also:
void Break_RAII_And_Leak()
{
RAII* instance = new RAII(); //breaks RAII because instance is leaked when this function exits.
}
void Not_RAII_And_Safe()
{
RAII* instance = new RAII(); //fine..
delete instance; //fine..
//however, you've done the deleting and cleaning up yourself / manually.
//that defeats the purpose of RAII.
}
Now take for example the following class:
class RAII_WITH_EXCEPTIONS
{
private:
char* SomeResource;
public:
RAII_WITH_EXCEPTIONS() : SomeResource(new char[1024]) {} //allocated 1024 bytes.
void ThrowException() {throw std::runtime_error("Error.");}
~RAII_WITH_EXCEPTIONS() {delete[] SomeResource;} //cleaned up allocation.
RAII_WITH_EXCEPTIONS(const RAII_WITH_EXCEPTIONS& other) = delete;
RAII_WITH_EXCEPTIONS(RAII_WITH_EXCEPTIONS&& other) = delete;
RAII_WITH_EXCEPTIONS& operator = (RAII_WITH_EXCEPTIONS &other) = delete;
};
and the following functions:
void RAII_Handle_Exception()
{
RAII_WITH_EXCEPTIONS RAII; //create an instance.
RAII.ThrowException(); //throw an exception.
//Event though an exception was thrown above,
//RAII's destructor is still called
//and the allocation is automatically cleaned up.
}
void RAII_Leak()
{
RAII_WITH_EXCEPTIONS* RAII = new RAII_WITH_EXCEPTIONS();
RAII->ThrowException();
//Bad because not only is the destructor not called, it also leaks the RAII instance.
}
void RAII_Leak_Manually()
{
RAII_WITH_EXCEPTIONS* RAII = new RAII_WITH_EXCEPTIONS();
RAII->ThrowException();
delete RAII;
//Bad because you manually created a new instance, it throws and delete is never called.
//If delete was called, it'd have been safe but you've still manually allocated
//and defeated the purpose of RAII.
}
fstream always did this. When you create an fstream instance on the stack, it opens a file. when the calling function exists, the fstream is automatically closed.
The same is NOT true for FILE* because FILE* is NOT a class and does NOT have a destructor. Thus you must close the FILE* yourself!
EDIT: As pointed out in the comments below, there was a fundamental problem with the code above. It is missing a copy constructor, a move constructor and assignment operator.
Without these, trying to copy the class would create a shallow copy of its inner resource (the pointer). When the class is destructed, it would have called delete on the pointer twice! The code was edited to disallow copying and moving.
For a class to conform with the RAII concept, it must follow the rule for three: What is the copy-and-swap idiom?
If you do not want to add copying or moving, you can simply use delete as shown above or make the respective functions private.
Here's a problem scenario: I've got a C++ object that includes a Cleanup() virtual method that needs to be called just before the object is destroyed. In order to do the right thing, this Cleanup method needs access to the fully-formed object (including subclass data), so I can't just call Cleanup() at the start of my own class's destructor, because by the time my class's destructor is called, the destructors any subclasses have already completed and they may have already freed some data that Cleanup() needed to look at.
The obvious solution would be to require the calling code to manually call my routine before deleting the object:
theObject->Cleanup();
delete theObject;
but that solution is fragile, since sooner or later somebody (probably me) will forget to call Cleanup() and bad things will happen.
Another solution would be to have a "holder" object that implements the pImpl technique to wrap the class, and have the holder object's destructor call Cleanup() on the object before deleting the object; but that solution isn't 100% desirable either, since it makes the class work differently from a standard C++ class and makes it impossible to allocate the object on the stack or statically.
So the question is, is there some clever technique (either in C++ or C++11) that I could use to tell the compiler to automatically call a specified (presumably virtual) method on my object before it calls the first subclass-destructor?
(come to think of it, a similar mechanism for automatically calling an Init() method -- just after the last subclass-constructor completes -- might be handy as well)
Lateral thinking: get rid of the Cleanup method, that's what a virtual destructor is for.
The very goal of a virtual destructor is to allow the outmost derived class destructor to be called when delete basepointer; is executed; and as RAII demonstrated, cleanup is the destructor's job.
Now you might argue that you would like an early Cleanup method, to ease the task of the destructor or maybe to reuse the object (kinda like a Reset method in a way). In practice, it rapidly turns into a maintenance nightmare (too easy to forget to clean one field and have state leak from one use to another).
So ask yourself the question: Why not use the destructor for what it's been created for ?
You can use a twist on the PIMPL wrapper:
class PIMPL
{
MyDataThatNeedsInitDestroy object;
public:
PIMPL(Atgs a)
: object(a)
{
object.postCreationInit();
}
~PIMP()
{
object.preDestructionDestory();
}
// All other methods are available via -> operator
MyDataThatNeedsInitDestroy* operator->() { return &object);
};
Yes, this can be done with virtual inheritance, because virtual base subobjects are always constructed (and destroyed) by the most-derived type, and the order of construction (and destruction) of base classes is well-defined also.
Of course, you also may make the delete operator private, and provide a Release() member function consisting of Cleanup(); delete this; But that wouldn't help with stack-allocated objects.
struct B
{
void cleanup()
{
if (!m_bCleanedUp)
{
m_bCleanedUp = true;
...
}
}
virtual B::~B()
{
assert(m_bCleanedUp);
...
}
bool m_bCleanedUp = false;
};
struct D : B
{
D::~D()
{
cleanup(); // if D author forgets, assert will fire
...
}
};
Is there a way to get a C++ class to automatically execute a method just before it starts executing the destructor?
You need to use smart pointer (shared_ptr - available in boost or c++11) with custom deleter instead of raw pointers.
typedef shared_ptr<MyClass> MyClassPtr;
class MyClassDeleter{
public:
void operator()(MyClass* p) const{
if (p)
p->cleanup();
delete p;
}
};
...
MyClassPtr ptr(new MyClass, MyClassDeleter());
--EDIT--
This will work for dynamically allocated objects. There is no solution (I can think of) for stack-allocated objects, so the reasonable action would be to make constructors private and make friend factory method that returns shared_ptr to constructed object - assuming you really need this mechanism.
I have objects which create other child objects within their constructors, passing 'this' so the child can save a pointer back to its parent. I use boost::shared_ptr extensively in my programming as a safer alternative to std::auto_ptr or raw pointers. So the child would have code such as shared_ptr<Parent>, and boost provides the shared_from_this() method which the parent can give to the child.
My problem is that shared_from_this() cannot be used in a constructor, which isn't really a crime because 'this' should not be used in a constructor anyways unless you know what you're doing and don't mind the limitations.
Google's C++ Style Guide states that constructors should merely set member variables to their initial values. Any complex initialization should go in an explicit Init() method. This solves the 'this-in-constructor' problem as well as a few others as well.
What bothers me is that people using your code now must remember to call Init() every time they construct one of your objects. The only way I can think of to enforce this is by having an assertion that Init() has already been called at the top of every member function, but this is tedious to write and cumbersome to execute.
Are there any idioms out there that solve this problem at any step along the way?
Use a factory method to 2-phase construct & initialize your class, and then make the ctor & Init() function private. Then there's no way to create your object incorrectly. Just remember to keep the destructor public and to use a smart pointer:
#include <memory>
class BigObject
{
public:
static std::tr1::shared_ptr<BigObject> Create(int someParam)
{
std::tr1::shared_ptr<BigObject> ret(new BigObject(someParam));
ret->Init();
return ret;
}
private:
bool Init()
{
// do something to init
return true;
}
BigObject(int para)
{
}
BigObject() {}
};
int main()
{
std::tr1::shared_ptr<BigObject> obj = BigObject::Create(42);
return 0;
}
EDIT:
If you want to object to live on the stack, you can use a variant of the above pattern. As written this will create a temporary and use the copy ctor:
#include <memory>
class StackObject
{
public:
StackObject(const StackObject& rhs)
: n_(rhs.n_)
{
}
static StackObject Create(int val)
{
StackObject ret(val);
ret.Init();
return ret;
}
private:
int n_;
StackObject(int n = 0) : n_(n) {};
bool Init() { return true; }
};
int main()
{
StackObject sObj = StackObject::Create(42);
return 0;
}
Google's C++ programming guidelines have been criticized here and elsewhere again and again. And rightly so.
I use two-phase initialization only ever if it's hidden behind a wrapping class. If manually calling initialization functions would work, we'd still be programming in C and C++ with its constructors would never have been invented.
Depending on the situation, this may be a case where shared pointers don't add anything. They should be used anytime lifetime management is an issue. If the child objects lifetime is guaranteed to be shorter than that of the parent, I don't see a problem with using raw pointers. For instance, if the parent creates and deletes the child objects (and no one else does), there is no question over who should delete the child objects.
KeithB has a really good point that I would like to extend (in a sense that is not related to the question, but that will not fit in a comment):
In the specific case of the relation of an object with its subobjects the lifetimes are guaranteed: the parent object will always outlive the child object. In this case the child (member) object does not share the ownership of the parent (containing) object, and a shared_ptr should not be used. It should not be used for semantic reasons (no shared ownership at all) nor for practical reasons: you can introduce all sorts of problems: memory leaks and incorrect deletions.
To ease discussion I will use P to refer to the parent object and C to refer to the child or contained object.
If P lifetime is externally handled with a shared_ptr, then adding another shared_ptr in C to refer to P will have the effect of creating a cycle. Once you have a cycle in memory managed by reference counting you most probably have a memory leak: when the last external shared_ptr that refers to P goes out of scope, the pointer in C is still alive, so the reference count for P does not reach 0 and the object is not released, even if it is no longer accessible.
If P is handled by a different pointer then when the pointer gets deleted it will call the P destructor, that will cascade into calling the C destructor. The reference count for P in the shared_ptr that C has will reach 0 and it will trigger a double deletion.
If P has automatic storage duration, when it's destructor gets called (the object goes out of scope or the containing object destructor is called) then the shared_ptr will trigger the deletion of a block of memory that was not new-ed.
The common solution is breaking cycles with weak_ptrs, so that the child object would not keep a shared_ptr to the parent, but rather a weak_ptr. At this stage the problem is the same: to create a weak_ptr the object must already be managed by a shared_ptr, which during construction cannot happen.
Consider using either a raw pointer (handling ownership of a resource through a pointer is unsafe, but here ownership is handled externally so that is not an issue) or even a reference (which also is telling other programmers that you trust the referred object P to outlive the referring object C)
A object that requires complex construction sounds like a job for a factory.
Define an interface or an abstract class, one that cannot be constructed, plus a free-function that, possibly with parameters, returns a pointer to the interface, but behinds the scenes takes care of the complexity.
You have to think of design in terms of what the end user of your class has to do.
Do you really need to use the shared_ptr in this case? Can the child just have a pointer? After all, it's the child object, so it's owned by the parent, so couldn't it just have a normal pointer to it's parent?