在类中包装Windows句柄
Wrapping Windows Handles in a class
我正在编写一个c++框架,以便我可以重写一些软件以在多个平台上工作。我的问题与一些使用Windows句柄的包装器类的实现有关。考虑下面的代码…
class Font
{
public:
Font(const LOGFONT& lf)
{
m_hFont = ::CreateFontIndirect(lf);
}
~Font()
{
::DeleteObject(m_hFont);
}
private:
HFONT m_hFont;
}
然后我有一个Display类,我可以调用下面的…
LOGFONT lf;
// initialise lf
Display d;
d.SetFont(Font(lf));
d.DrawText(0,0,"Some Text");
问题当然是d.SetFont会导致m_hFont被Font类析构函数删除。我很感激我可以在堆上创建字体,并让图形类负责字体的整体"生命周期"。我想这真的是一个设计问题。是……好吗?
- 为包装Windows句柄的类实现引用计数
- 在堆上创建包装器类。
- 其他方法?
我注意到MFC在它们的包装器中有一个显式的DeleteObject,但这当然不会导致自动的资源回收。
感谢任何帮助/建议。
感谢编辑:我认为这更像是一个复制构造函数问题。例如,我的Font类创建了一个Windows Font句柄,但由于我将Font对象按值传递给显示而被销毁。
您至少有三个选择:
-
注意"三原则":如果一个类有一个非平凡的析构函数,那么它可能还应该实现一个复制构造函数和一个复制赋值操作符。在这种情况下,他们应该确保每个副本都有自己的
m_hFont
版本。 -
使用引用计数
-
更改
Display::SetFont
以接受指向Font
或const引用的指针。这样你仍然可以创建Font
"在堆栈上",如果你只传递一个指针或引用到它,将不会复制。
如果你让
Display::SetFont
直接接受LOGFONT
,你可能能够完全避免这个问题。这样,Display
类本身将管理字体(例如,删除旧的字体结构并创建新的)。如果您计划仅在上面的上下文中(与Display
一起)使用Font
对象,并且字体更改很少,则此选项最有效。使
Font
类也将LOGFONT
作为成员,并仅在需要时生成HFONT。当复制时,LOGFONT
将被复制,HFONT
将被赋予一个无效的值。如果新的Font::GetFont
被调用(比如被Display
调用),那么HFONT
将被创建。在Font析构函数中,如果HFONT
不是无效值,则删除它。这将避免一些不必要的调用CreateFontIndirect
,如果不是所有的副本将被用来调用GetFont
。
这就是Windows的本质。当你以像调用CreateFontIndirect这样的方式使用资源时,你必须调用DeleteObject或某种方法来在你完成时释放资源。到底是什么问题?您的程序是否没有按照预期运行?它应该没问题,除非在使用它之前它超出了作用域。
根据答案的建议和一些进一步的思考,我采用了以下方法。我认为Display类应该管理字体的生命周期。库用户将为显示类提供字体设置。基本代码如下:
struct Typeface
{
bool Bold;
int Width;
int Height;
};
class Font
{
public:
Font();
~Font(); // calls DeleteObject(m_hFont)
HFONT Handle() const { return m_hFont; }
// Create will destroy the current font handle and create a new one
void Create(const Typeface & tc);
private:
HFONT m_hFont;
};
class Display
{
public:
// select font modifies the display's current font
void SelectFont(const Typeface& tf);
// Draw a string using the display's selected font
void DrawString(int x, int y, const String& text);
// Draw a string using the supplied font
void DrawString(int x, int y, const String& text, const Font& font);
private:
Font m_hSelectedFont; // Font handle automatically destroyed
};
我认为这是c++ 20中最方便的解决方案:
using XHFONT = unique_ptr<remove_reference_t<decltype(*HFONT())>, decltype([]( HFONT hf ) { hf && DeleteObject( hf ); })>;
,unique_ptr<的在只能管理指针的数据,但幸运的是,Windows句柄总是指针,通常用DECLARE_HANDLE声明,你可以为任何Windows句柄类型声明包装器,除了HANDLE,因为HANDLE只是一个空指针,其中remove_reference_t<decltype(*HFONT())>不工作。
- Windows 函数"GetCursorInfo"返回成功,但光标的句柄为 NULL
- 假定 Windows 伪句柄的值是否安全/定义?
- Windows句柄始终返回Invalid_handle_value
- 编写 Windows 桌面应用程序时,我应该在哪里跟踪我的窗口句柄?
- Windows HANDLE RAII 管理,如果返回布尔值而不是句柄怎么办?
- 改进 Windows 句柄上的 RAI 模板类?
- 尝试打开显示设备句柄以使用 C++ 更改 Windows XP 上的亮度
- 错误 6 句柄在 Windows 上写入文件无效
- 如何在Windows中获取当前进程的所有子进程的句柄
- Windows -- 继承子进程中的控制台文件句柄
- 检索 Windows 资源管理器的地址栏编辑控件的句柄
- 从Windows中的父进程继承句柄
- 便携式设备的Windows句柄
- 如何使用Windows应用商店C++在没有窗口句柄的情况下渲染路径几何体
- c++ boost asio Windows文件句柄async_read_until无限循环-没有eof.< /
- 需要通过引用类传递Windows事件句柄的帮助
- Windows窗体面板.Java swing中的句柄等价
- 依赖于Windows句柄的类型是否为指针
- 在类中包装Windows句柄
- 在注册表中存储和使用 Windows 句柄 (WId)