关于用vector管理CImage时遇到的坑

2023-11-17

假设有一个类A,里面有一个CImage。如果用vector储存,erase前面的元素后,后面的CImage就无法使用,会报ATLASSERT( hBitmap == m_hBitmap );检查失败

struct A
{
    CImage img;
};

int _tmain(int argc, _TCHAR* argv[])
{
    vector<A> imgs(2);
    imgs[0].img.Create(1, 1, 32);
    imgs[1].img.Create(1, 1, 32);

    // 正常工作
    imgs[0].img.GetDC();
    imgs[0].img.ReleaseDC();
    imgs[1].img.GetDC();
    imgs[1].img.ReleaseDC();

    imgs.erase(imgs.begin());      // 删除第一个img
    imgs[0].img.GetDC();
    imgs[0].img.ReleaseDC();       // 出错,ATLASSERT( hBitmap == m_hBitmap );检查失败

    return 0;
}

GetDC和ReleaseDC是这样的

inline HDC CImage::GetDC() const throw()
{
    ATLASSUME( m_hBitmap != NULL );

    m_nDCRefCount++;
    if( m_hDC == NULL )
    {
        m_hDC = GetCDCCacheInstance()->GetDC();
        m_hOldBitmap = HBITMAP( ::SelectObject( m_hDC, m_hBitmap ) );
    }

    return( m_hDC );
}

inline void CImage::ReleaseDC() const throw()
{
    HBITMAP hBitmap;

    ATLASSUME( m_hDC != NULL );

    m_nDCRefCount--;
    if( m_nDCRefCount == 0 )
    {
        hBitmap = HBITMAP( ::SelectObject( m_hDC, m_hOldBitmap ) );
        ATLASSERT( hBitmap == m_hBitmap );
        GetCDCCacheInstance()->ReleaseDC( m_hDC );
        m_hDC = NULL;
    }
}

调试看了一下,ReleaseDC里的SelectObject返回值是NULL,更神奇的是上一句的GetDC里的SelectObject返回值也是NULL。看了一下SelectObject的文档,当调用失败时才返回NULL,而且一张BITMAP不能选入多个DC中。不过这里的BITMAP也没有选入多个DC啊,想了半天也没想出什么错误,直到我偶然调试到CImage的析构函数时发现,vector中的两个img的hBitmap居然是一样的

vector内存

仔细想想,应该是vector删除前面元素时需要把后面的元素往前移动,然后不小心把后面的元素拷贝了一份,然后在后面元素的析构函数中把hBitmap释放了。查看erase的实现证实了我的想法

        // TEMPLATE FUNCTION move
template<class _InIt,
    class _OutIt> inline
    _OutIt _Move(_InIt _First, _InIt _Last,
        _OutIt _Dest, _Nonscalar_ptr_iterator_tag)
    {   // move [_First, _Last) to [_Dest, ...), arbitrary iterators
    for (; _First != _Last; ++_Dest, ++_First)
        *_Dest = _STD move(*_First);  // 由于CImage没有实现移动的=操作符,这里调用了默认的拷贝的=操作符
    return (_Dest);
    }

解决方法:

  1. 自己实现移动的=操作符

    struct A
    {
      A& operator= (A&& other)
      {
          img.Destroy();
          img.Attach(other.img.Detach());
          return *this;
      }
    
      CImage img;
    };
    
  2. 用指针管理CImage

    int _tmain(int argc, _TCHAR* argv[])
    {
      vector<unique_ptr<A> > imgs;
      imgs.push_back(make_unique<A>());
      imgs.push_back(make_unique<A>());
      imgs[0]->img.Create(1, 1, 32);
      imgs[1]->img.Create(1, 1, 32);
    
      // 正常工作
      imgs.erase(imgs.begin());
      imgs[0]->img.GetDC();
      imgs[0]->img.ReleaseDC();
    
      return 0;
    }
    
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

关于用vector管理CImage时遇到的坑 的相关文章

  • 为什么使用abs()或fabs()而不是条件否定?

    在 C C 中 为什么要使用abs or fabs 不使用以下代码即可查找变量的绝对值 int absoluteValue value lt 0 value value 这与较低级别的指令较少有关吗 您提出的 有条件的abs 并不等于std
  • C++ 中的软(不是:弱)引用 - 这可能吗?有实施吗?

    在 C 中我正在使用boost shared ptr and boost weak ptr自动删除不再需要的对象 我知道这些与引用计数一起工作 在 Java 中 内存由垃圾收集器管理 它将内置对象引用视为strong WeakReferen
  • 在 C++ 中分割大文件

    我正在尝试编写一个程序 该程序接受一个大文件 任何类型 并将其分成许多较小的 块 我想我已经有了基本的想法 但由于某种原因我无法创建超过 12 kb 的块大小 我知道谷歌等上有一些解决方案 但我更感兴趣的是了解这个限制的根源是什么 然后实际
  • TextBox 焦点的 WinForms 事件?

    我想添加一个偶数TextBox当它有焦点时 我知道我可以用一个简单的方法来做到这一点textbox1 Focus并检查布尔值 但我不想那样做 我想这样做 this tGID Focus new System EventHandler thi
  • 获取从属性构造函数内部应用到哪个属性的成员?

    我有一个自定义属性 在自定义属性的构造函数内 我想将属性的属性值设置为属性所应用到的属性的类型 是否有某种方式可以访问该属性所应用到的成员从我的属性类内部 可以从 NET 4 5 using CallerMemberName Somethi
  • 如何在 VS 中键入时显示方法的完整文档?

    标题非常具有描述性 是否有任何扩展可以让我看到我正在输入的方法的完整文档 我想查看文档 因为我可以在对象浏览器中看到它 其中包含参数的描述和所有内容 而不仅仅是一些 摘要 当然可以选择查看所有覆盖 它可能是智能感知的一部分 或者我不知道它并
  • C++11 函数局部静态 const 对象的线程安全初始化

    这个问题已在 C 98 上下文中提出 并在该上下文中得到回答 但没有明确说明有关 C 11 的内容 const some type create const thingy lock my lock some mutex static con
  • 禁用 LINQ 上下文的所有延迟加载或强制预先加载

    我有一个文档生成器 目前包含约 200 个项目的查询 但完成后可能会超过 500 个 我最近注意到一些映射表示延迟加载 这给文档生成器带来了一个问题 因为它需要根据生成的文档来访问所有这些属性 虽然我知道DataLoadOptions可以指
  • 两组点之间的最佳匹配

    I ve got two lists of points let s call them L1 P1 x1 y1 Pn xn yn and L2 P 1 x 1 y 1 P n x n y n 我的任务是找到它们点之间的最佳匹配 以最小化它
  • 通过不同 DLL 或 EXE 中的指针或引用访问 STL 对象时发生访问冲突

    我在使用旧版 VC6 时遇到以下问题 我只是无法切换到现代编译器 因为我正在处理遗留代码库 http support microsoft com kb 172396 http support microsoft com kb 172396
  • 组合框项目为空但数据源已满

    将列表绑定到组合框后 其 dataSource Count 为 5 但组合框项目计数为 0 怎么会这样 我习惯了 Web 编程 而且这是在 Windows 窗体中进行的 所以不行combo DataBind 方法存在 这里的问题是 我试图以
  • 如何排列表格中的项目 - MVC3 视图 (Index.cshtml)

    我想使用 ASP NET MVC3 显示特定类型食品样本中存在的不同类型维生素的含量 如何在我的视图 Index cshtml 中显示它 an example 这些是我的代码 table tr th th foreach var m in
  • 通过等待任务或访问其 Exception 属性都没有观察到任务的异常

    这些是我的任务 我应该如何修改它们以防止出现此错误 我检查了其他类似的线程 但我正在使用等待并继续 那么这个错误是怎么发生的呢 通过等待任务或访问其 Exception 属性都没有观察到任务的异常 结果 未观察到的异常被终结器线程重新抛出
  • C# 搜索目录中包含字符串的所有文件,然后返回该字符串

    使用用户在文本框中输入的内容 我想搜索目录中的哪个文件包含该文本 然后我想解析出信息 但我似乎找不到该字符串或至少返回信息 任何帮助将不胜感激 我当前的代码 private void btnSearchSerial Click object
  • 32位PPC rlwinm指令

    我在理解上有点困难rlwinmPPC 汇编指令 旋转左字立即然后与掩码 我正在尝试反转函数的这一部分 rlwinm r3 r3 0 28 28 我已经知道什么了r3 is r3在本例中是一个 4 字节整数 但我不确定这条指令到底是什么rlw
  • Fluent NHibernate 日期时间 UTC

    我想创建一个流畅的 nhibernate 映射来通过以下方式映射 DateTime 字段 保存时 保存 UTC 值 读取时 调整为本地时区值 实现此映射的最佳方法是什么 就我个人而言 我会将日期存储在 UTC 格式的对象中 然后在读 写时在
  • 我应该在应用程序退出之前运行 Dispose 吗?

    我应该在应用程序退出之前运行 Dispose 吗 例如 我创建了许多对象 其中一些对象具有事件订阅 var myObject new MyClass myObject OnEvent OnEventHandle 例如 在我的工作中 我应该使
  • 为什么 Ajax.BeginForm 在 Chrome 中不起作用?

    我正在使用 c NET MVC2 并尝试创建一个 ajax 表单来调用删除数据库记录 RemoveRelation 的方法 删除记录的过程正在按预期进行 删除记录后 表单应调用一个 JavaScript 函数 从视觉效果中删除该记录 Rem
  • Swagger 为 ASP.CORE 3 中的字典生成错误的 URL

    当从查询字符串中提取的模型将字典作为其属性之一时 Swagger 会生成不正确的 URL 如何告诉 Swagger 更改 URL 中字典的格式或手动定义输入参数模式而不自动生成 尝试使用 Swashbuckle 和 NSwag 控制器 pu
  • 如何创建向后兼容 Windows 7 的缩放和尺寸更改每显示器 DPI 感知应用程序?

    我是 WPF 和 DPI 感知 API 的新手 正在编写一个在 Windows 7 8 1 和 10 中运行的应用程序 我使用具有不同每个显示器 DPI 设置的多个显示器 并且有兴趣将我的应用程序制作为跨桌面配置尽可能兼容 我已经知道可以将

随机推荐

  • llama.cpp LLM模型 windows cpu安装部署;运行LLaMA2模型测试

    参考 https www listera top ji xu zhe teng xia chinese llama alpaca https blog csdn net qq 38238956 article details 1301135
  • 设置linux-kali 2022语言为中文(保姆级图文)

    目录 友情提示 1 打开终端 2 打开设置 3 修改设置 4 重启生效设置 总结 欢迎关注 网络工程专业 系列 持续更新中 欢迎关注 网络工程专业 系列 持续更新中 在安装完 kali linux2022 时 操作系统默认语言为英文 初学者
  • 【论文阅读-TPAMI2021】Curriculum Learning(课程学习)综述

    简介 Curriculum learning CL 课程学习 是一种模型训练策略 通过先让模型学习简单数据后再学习困难数据的方式模拟学生进行课程学习的场景 通用的课程学习框架为Difficulty Measurer 困难程度评估 Train
  • 不懂Python装饰器,你敢说会Python?

    对于Python学习者 一旦过了入门阶段 你几乎一定会用到Python的装饰器 它经常使用在很多地方 比如Web开发 日志处理 性能搜集 权限控制等 还有一个极其重要的地方 那就是面试的时候 对 装饰器是面试中最常见的问题之一 实战入门 抛
  • webpack从入门到放弃(二:基本属性)

    本节介绍webpack五大核心概念 一 entry 入口 指示 Webpack 从哪个文件开始打包 webpack是根据依赖关系进行打包 以入口文件为起点 根据依赖关系形成依赖树 在生产模式打包时 根据tree shaking未引用的文件不
  • 8259初始化命令字(ICW1-ICW4)

    8259A的中断操作功能很强 包括中断的请求 屏蔽 排队 结束 级联以及提供中断类型号和查询等操作 并且其操作的方式又有不同 它既能实现向量中断 又能进行中断查询 它可以用于16位机 也可用于8位机 因此 使用起来感到复杂且不好掌握 为此
  • idea 提交远程库冲突解决

    idea 提交远程库冲突解决 github团队协作 正常开发 管理得好的话 不会出现代码冲突问题 项目经理会划分模块 每个小组成员各自开发模块 公共的代码由专门的人负责维护 但是偶尔管理沟通问题导致出现冲突偶尔也是会出现的 冲突出现场景过程
  • Visual Studio Code中英文的切换

    我在学习 Flutter 的时候 使用过 VsCode 来开发 一般来说 安装好的 VsCode 都是英文版的 有些人可能不太习惯用英文版的 不过没有关系 我在这里提供中英文切换的方法给大家 切换为中文 1 点击 1 中的选项 在 2 中的
  • java栈溢出现象_JVM源码分析之栈溢出完全解读

    概述 之所以想写这篇文章 其实是因为最近有不少系统出现了栈溢出导致进程crash的问题 并且很隐蔽 根本原因还得借助coredump才能分析出来 于是想从JVM实现的角度来全面分析下栈溢出的这类问题 或许你碰到过如下的场景 日志里出现了St
  • python uiautomator2 init 作用

    目录 背景 具体步骤 总结 背景 在搭建Python的自动化测试环境时 执行脚本一直报错 ions GatewayError Uiautomator started failed
  • (Linux)docker容器安装Kibana--简单安装

    docker容器安装Kibana docker容器安装Kibana 启动Kibana docker容器安装Kibana 使用docker命令安装Kibana容器 sudo docker pull kibana 7 4 2 等待下载安装完成
  • matlab 2022更新

    matlab 2022b dictionary 对象 将唯一键映射到值以便快速查找 深度学习工具箱 直接导入 PyTorch 模型 将模型导出到 TensorFlow Simulink 将库浏览器停靠在模型中 MATLAB NET 引擎 A
  • Bootstrap JavaScript插件:警告信息 (alert.js)

    作者 WangMin 格言 努力做好自己喜欢的每一件事 CSDN原创文章 博客地址 WangMin 警告框插件 alert js 为警告框组件一个关闭功能 就是点击警告框的关闭按钮 可以让警告框消失 并将它从 DOM 中删除 使用方法 1
  • SpringBoot+ActiveMQ-点对点队列模式(消费端)

    ActiveMQ消息中间件的点对点模式point to point 消息队列 生产端案例 配合消费端测试 SpringBoot ActiveMQ生产端 ActiveMQ版本 apache activemq 5 16 5 SpringBoot
  • C#基础教程

    我的第一个 C 程序 Console WriteLine Hello World Console ReadKey 编写 Console Readkey 这个函数是为了在控制台窗口停留一下 直到敲击键盘为止 不然运行时 Hello World
  • 树莓派开机启动终端运行方法

    在路径 home pi config autostart 下建立一个文本文本 并以后缀名 desktop 结尾 根据是否需要显示终端 写入下面两段内容之一 显示终端启动 Desktop Entry Name testboot Icon ut
  • 基于SpringBoot的校园请假管理系统

    全网粉丝20W csdn特邀作者 博客专家 CSDN新星计划导师 java领域优质创作者 博客之星 掘金 华为云 阿里云 InfoQ等平台优质作者 专注于Java技术领域和毕业项目实战 文末获取项目下载方式 一 项目背景介绍 校园请假信息管
  • ruoyi若依获取当前登录用户以及用户信息

    this store state user 登录成功 有token情况下 直接打印这个
  • matlab knn回归,(25条消息)KNN算法matlab函数 ClassificationKNN.fit

    mdl ClassificationKNN fit X Y 基于特征和分类标签返回分类模型 X 每行表示一个特征向量 每列表示特征向量中一个变量 Y 每行代表的是X中特征向量说代表的标签或种类 mdl ClassificationKNN f
  • 关于用vector管理CImage时遇到的坑

    假设有一个类A 里面有一个CImage 如果用vector储存 erase前面的元素后 后面的CImage就无法使用 会报ATLASSERT hBitmap m hBitmap 检查失败 struct A CImage img int tm