开发者

C++ RAII Questions

So as I understand it to implement RAII properly, if I where to call CreateFont, I'd wrap that in a cl开发者_JAVA技巧ass 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.


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:

  • is it a problem? The classes will be small and easy to read and understand,
  • you might be able to reuse many of them (for example, there are a lot of Win32 functions which create HANDLE objects, and they're all closed the same way (with CloseHandle), so you could reuse the same class for those.
  • you can use a smart pointer or some other generic wrapper to fill in most of the boilerplate code. The most popular smart pointer classes allow you to specify a custom deleter function.

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're going for solid RAII, there are some options for reducing the number of classes you'll need - for example, some boost smart pointers (shared_ptr specifically) allow you to provide your own function to call when the pointer goes out of scope.

Otherwise, yes - you'll have a class for any resource which requires explicit freeing - and while it's a pain in the butt code-wise, it will save you massive time in debugging in the long run (especially in group projects). I'd still say to use RAII based on your own feelings on the situation though - it's a wonderful idea to use it everywhere, but some times when converting old code it can be a massive amount of work to fix all the call-chains up to use it.

One more thing - I'm not overly familiar with the GUI logic you're working with, so I won't go there specifically... but you'll have to look into how your resources should be copied and how long they should be maintained. Will your RAII containers be reference counting, or will they have value (copy) semantics? Reference counting smart-pointers like shared_ptr may solve your problem about recreation of resources frequently as long as you can pass a reference to the original around your code.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜