So as I understand it to implement RAII properly, if I where to call CreateFont
, I'd wrap that in a class with CreateFont
in the constructor and DeleteObject
in the destructor, so it cleans it up when it goes out of scope.
First question is, won't I end up with ALOT of classes doing that? Especially since the class only has a constructor and destructor.
Second question is, what if I'm calling the CreateFont class in the WndProc, that goes out of scope constantly. So am I supposed to do all my calls to CreateFont
or like LoadBitmap
in the WndMain?
I'm used to calling those functions in WM_CREATE
and cleaning them up in WM_DESTROY
.
C does not have RAII-like memory management in any way. Exceptions work beautifully with memory management like that, but if it's not there, you can't just say it should work because memory management should work like that.
The principle that objects own resources is also known as "resource acquisition is initialization," or RAII. When a resource-owning stack object goes out of scope, its destructor is automatically invoked. In this way, garbage collection in C++ is closely related to object lifetime, and is deterministic.
Smart pointers will use the RAII philosophy to ensure that heap allocated objects are destroyed any time the pointer variable is destroyed. In addition - pointers are the most common application of RAII - you'll likely allocate thousands of times more pointers than any other resource.
Resource Acquisition Is Initialization or RAII, is a C++ programming technique which binds the life cycle of a resource that must be acquired before use (allocated heap memory, thread of execution, open socket, open file, locked mutex, disk space, database connection—anything that exists in limited supply) to the ...
You can avoid a lot of repetitious work by using a template to help you. For example if you use boost::shared_ptr
you can do:
#include <boost/shared_ptr.hpp>
#include <functional>
struct Font;
Font *createFont();
void deleteFont(Font*);
int main() {
boost::shared_ptr<Font> font(createFont(), std::ptr_fun(deleteFont));
}
Which saves you writing a custom class to manage the resource. If boost and TR1 or newer aren't available to you it's still possible to implement something similar and generic yourself to assist.
boost::shared_ptr
is reference counted properly, so if you want to create it somewhere and "promote" it to live longer later you can do so by copying it somewhere longer lived before it dies.
First question is, won't I end up with ALOT of classes doing that? Especially since the class only has a constructor and destructor.
Yes, but there are few points to consider:
HANDLE
objects, and they're all closed the same way (with CloseHandle
), so you could reuse the same class for those.Second question is, what if I'm calling the CreateFont class in the WndProc, that goes out of scope constantly.
Store it in a location where it won't go out of scope prematurely. :)
Here, smart pointers might be useful again. For example, shared_ptr
could be used to keep the font alive as long as there's at least one shared_ptr
pointing to it. Then you can simply pass it out of the function to some common longer-lived location.
Otherwise, as long as you implement copy constructor and assignment operator (in C++11 you might want to implement move constructor and move assignment instead) for your RAII class, it can be copied (or moved) safely to wherever you want to put it, even if it was created in a smaller scope.
First question is, won't I end up with ALOT of classes doing that? Especialy since the class only has a constructor and deconstructor
If you don't like the number of classes you'd need to create for each different type of object, you can create a single RAII class that takes a HGDIOBJ parameter in the constructor and calls DeleteObject in the destructor. This class can then be used for all the different GDI objects. For example:
class GDIObject
{
public:
HGDIOBJ GdiObject;
GDIObject( HGDIOBJ object )
: GdiObject( object )
{
}
~GDIObject()
{
DeleteObject( GdiObject );
}
}
...
GDIObject font( CreateFont( 48, 0, 0, 0, FW_DONTCARE, false, true, false, DEFAULT_CHARSET, OUT_OUTLINE_PRECIS, CLIP_DEFAULT_PRECIS, CLEARTYPE_QUALITY, VARIABLE_PITCH, TEXT("Impact") ) );
Second question is, what if I'm calling the CreateFont class in the WndProc, that goes out of scope constantly. So am i supposed to do all my calls to CreateFont or like LoadBitmap in the WndMain? I'm used to calling those functions in WM_CREATE and cleaning them up in WM_DESTROY.
For items that need to remain in-memory for longer than the function scope, you'll have to put these at the global level.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With