我正在编写一个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类析构函数删除。我很欣赏我可以在堆上创建字体,并让图形类负责Font的整体"生命周期"。我想这确实是一个设计问题。是不是更好......
我注意到MFC在其包装器中有一个显式的DeleteObject,但这当然不会导致自动资源解除分配。
任何帮助/建议表示赞赏。
由于
编辑:我认为这更像是一个复制构造函数问题。即我的Font类创建了一个Windows FONT句柄,但是因为我将Font对象按值传递给显示器而被销毁。答案 0 :(得分:1)
您至少有三个选择:
注意“三规则”:如果一个类有一个非平凡的析构函数,那么它应该也可以实现一个复制构造函数和一个复制赋值运算符。在这种情况下,他们应该确保每个副本都有自己的m_hFont
版本。
使用引用计数。
更改Display::SetFont
以接受指向Font
或const引用的指针。这样你仍然可以在堆栈上创建Font
“,如果你只传递指针或对它的引用,就不会有副本。
修改
如果您Display::SetFont
直接接受LOGFONT
,则可以完全避免此问题。这样,Display
类本身将管理字体(例如删除旧字体结构并创建新字体)。如果您计划仅在上面的上下文中使用Font
对象(使用Display
)并且字体更改很少,则此选项效果最佳。
让Font
类同时拥有LOGFONT
作为成员,并仅按需生成HFONT。复制后,LOGFONT
将被复制,HFONT
将被赋予无效值。如果调用新Font::GetFont
(例如Display
),则会创建HFONT
。在Font析构函数中,如果HFONT
不是无效值,则将其删除。如果不是所有副本都将用于调用CreateFontIndirect
,这将避免对GetFont
进行一些不必要的调用。
答案 1 :(得分:0)
这就是Windows的本质。当您以调用CreateFontIndirect这样的方式使用资源时,您必须在完成后调用DeleteObject或某种方法来释放资源。究竟是什么问题?你的程序没有按预期运行吗?除非在你使用它之前超出范围,否则应该没问题。
答案 2 :(得分:0)
根据答案的建议和进一步的想法,我采用了以下方法。我认为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
};