C++ RAII 问题

发布于 2024-12-06 16:36:04 字数 362 浏览 0 评论 0原文

因此,据我了解,要正确实现 RAII,如果我在哪里调用 CreateFont,我会将其包装在一个类中,在构造函数中使用 CreateFont 并使用 DeleteObject< /code> 在析构函数中,因此当它超出范围时它会清理它。

第一个问题是,我最终不会有很多课程这样做吗?特别是因为该类只有构造函数和析构函数。

第二个问题是,如果我在 WndProc 中调用 CreateFont 类,它会不断超出范围,该怎么办?那么我是否应该在 WndMain 中对 CreateFont 或 LoadBitmap 进行所有调用? 我习惯于在 WM_CREATE 中调用这些函数并在 WM_DESTROY 中清理它们。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

相思碎 2024-12-13 16:36:04

使用模板可以帮助您避免大量重复性工作。例如,如果您使用 boost::shared_ptr 您可以这样做:

#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));
}

这可以节省您编写自定义类来管理资源的时间。如果您无法使用 boost TR1 或更新版本,您仍然可以自己实现类似和通用的东西来提供帮助。

boost::shared_ptr 是正确的引用计数,因此,如果您想在某个地方创建它并“促进”它的寿命更长,您可以通过在它消失之前将其复制到寿命更长的地方来实现。

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.

寒江雪… 2024-12-13 16:36:04

第一个问题是,我最终不会有很多课程这样做吗?特别是因为该类只有构造函数和析构函数。

是的,但有几点需要考虑:

  • 这是一个问题吗?这些类将很小并且易于阅读和理解,
  • 您也许可以重用其中的许多类(例如,有很多创建 HANDLE 对象的 Win32 函数,并且它们都是封闭的同样的方式(使用CloseHandle),因此您可以重复使用相同的类,
  • 您可以使用智能指针或其他通用包装器来填充大多数最流行的智能指针。类允许您指定自定义删除器 功能。

第二个问题是,如果我在 WndProc 中调用 CreateFont 类,它会不断超出范围,该怎么办?

将其存储在不会过早超出范围的位置。 :)
在这里,智能指针可能再次有用。例如,只要至少有一个 shared_ptr 指向该字体,就可以使用 shared_ptr 来使该字体保持活动状态。然后,您可以简单地将其从函数中传递到某个常见的长期存在的位置。

否则,只要您为 RAII 类实现复制构造函数和赋值运算符(在 C++11 中,您可能希望实现移动构造函数和移动赋值),就可以将其安全地复制(或移动)到您想要放置的任何位置它,即使它是在较小的范围内创建的。

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.

Saygoodbye 2024-12-13 16:36:04

第一个问题是,我最终不会有很多课程这样做吗?特别是因为该类只有构造函数和解构函数

如果您不喜欢需要为每种不同类型的对象创建的类数量,您可以创建一个 RAII 类,该类在构造函数中采用 HGDIOBJ 参数并调用在析构函数中删除Object。该类可用于所有不同的 GDI 对象。例如:

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") ) );

第二个问题是,如果我在 WndProc 中调用 CreateFont 类,它会不断超出范围,该怎么办?那么我应该在 WndMain 中对 CreateFont 或 LoadBitmap 进行所有调用吗?我习惯在 WM_CREATE 中调用这些函数并在 WM_DESTROY 中清理它们。

对于需要在内存中保留的时间超过函数作用域的项目,您必须将它们放在全局级别。

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.

最美不过初阳 2024-12-13 16:36:04

如果您打算使用可靠的 RAII,有一些选项可以减少您需要的类的数量 - 例如,一些 boost 智能指针(特别是 shared_ptr)允许您提供自己的函数,以便在指针超出范围时调用范围。

否则,是的 - 您将为任何需要显式释放的资源提供一个类 - 虽然这在代码方面是一个痛苦,但从长远来看,它将节省您大量的调试时间(特别是在小组项目中)。不过,我仍然建议根据您自己对情况的感受来使用 RAII - 在任何地方使用它是一个很棒的主意,但有时在转换旧代码时,修复所有调用链可能需要大量工作使用它。

另一件事 - 我不太熟悉你正在使用的 GUI 逻辑,所以我不会专门去那里......但你必须研究你的资源应该如何复制以及它们应该复制多长时间被维护。您的 RAII 容器将采用引用计数,还是具有值(复制)语义?只要您可以在代码中传递对原始资源的引用,像shared_ptr这样的引用计数智能指针就可以经常解决有关资源重新创建的问题。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文