gpt4 book ai didi

c++ - 为什么 CDC::SelectObject(CFont*) 接受 CFont 对象而不是指针?

转载 作者:塔克拉玛干 更新时间:2023-11-02 23:23:19 25 4
gpt4 key购买 nike

    CPaintDC dc(this); 
CFont font;
dc.SelectObject(font); // why does this build?

函数CDC::SelectObject采用 CFont 类型的指针,但为什么要通过提供对象来构建?我遇到了这个问题,上面的代码是不可预测的,有时会崩溃,但并非总是如此。

最佳答案

有问题的代码在某种程度上是有效的。它的编译是由于两件事的结合:

当编译器尝试为 dc.SelectObject(font) 匹配重载时,它们都不匹配。因此接下来它会尝试返回 HFONT 的用户定义的转换运算符 (operator HFONT())。这与采用 HGDIOBJ 的未记录的重载相匹配(HGDIOBJHFONT 都被类型定义为 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/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com