- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
CPaintDC dc(this);
CFont font;
dc.SelectObject(font); // why does this build?
函数CDC::SelectObject采用 CFont
类型的指针,但为什么要通过提供对象来构建?我遇到了这个问题,上面的代码是不可预测的,有时会崩溃,但并非总是如此。
最佳答案
有问题的代码在某种程度上是有效的。它的编译是由于两件事的结合:
CFont::operator HFONT()
.CDC::SelectObject
重载采用 HGDIOBJ
句柄。当编译器尝试为 dc.SelectObject(font)
匹配重载时,它们都不匹配。因此接下来它会尝试返回 HFONT
的用户定义的转换运算符 (operator HFONT()
)。这与采用 HGDIOBJ
的未记录的重载相匹配(HGDIOBJ
和 HFONT
都被类型定义为 void*
)。
问题中发布的代码也几乎是正确的,但有 2 个异常(exception):
font
对象被销毁,同时仍被选择到设备上下文中。虽然这会导致双重删除错误(字体对象属于 CFont
实例和设备上下文),但对 DeleteFont
的调用传递无效句柄时优雅地失败。这两个问题都不会导致不可预测的行为或间歇性崩溃。如 your answer 中所述,然而,真正的代码看起来像这样:
CFont* pOldFont = (CFont*) dc.SelectObject(font);
这是一个表现出未定义行为的错误。 dc.SelectObject(font)
返回一个 HGDIOBJ
(类型定义为 void*
),随后将其转换为不相关的类型(CFont*
).虽然将先前选择的字体存储到设备上下文中以便稍后恢复它是正确的,但代码不是。尊重所有权的实现可以是:
CPaintDC dc(this);
CFont font;
CFont oldFont;
// Transfer ownership of font to the DC, and the previously selected font into oldFont
oldFont.Attach(dc.SelectObject(font.Detach()));
// Use dc
// Transfer ownership back
font.Attach(dc.SelectObject(oldFont.Detach()));
// oldFont goes out of scope; this a no-op since it no longer owns any resources
// font goes out of scope, releasing all resources owned by it
// dc goes out of scope, releasing all resources owned by objects selected into it
如果您愿意暂时牺牲严格的所有权语义,您可以通过使用更标准的实现让您的生活更轻松:
CPaintDC dc(this);
CFont font;
CFont* pOldFont = dc.SelectObject(&font);
// Use dc
dc.SelectObject(pOldFont);
这是安全的,即使您提前退出,也不会恢复设备上下文。它仍然会导致对 CFont
实例和设备上下文(由 API 妥善处理)所拥有的字体对象进行双重删除。不过,它并没有出现字体泄漏,因为事情比看起来更复杂:这里涉及另一个不可见的所有者,一个由 MFC 控制的映射,用于存储临时对象(比如从 CGdiObject::FromHandle
返回的那些, SelectObject(CFont*)
调用)。作为 MFC 空闲时间处理的一部分,临时对象被清理。
关于c++ - 为什么 CDC::SelectObject(CFont*) 接受 CFont 对象而不是指针?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48832422/
CPaintDC dc(this); CFont font; dc.SelectObject(font); // why does this build? 函数CDC::Select
我使用的是固定大小的字体(例如:“Courier New”)。当我通过调用 CFont::CreateFont 函数初始化 CFont 对象时,我只想指定字体高度。 CFont Font; Font.
我想知道,在以下情况下我需要调用 DeleteObject 吗? CFont* oldFont = label.GetFont(); LOGFONT oldLogFont; oldFont->GetL
我是一名优秀的程序员,十分优秀!