PS:明天上午,非常郁闷,有很多简单基础的问题搞得我有些迷茫,哎,代码几天不写就忘。目前又不当COO,还是得用心记代码哦!

BSTR应用误区以及隐藏的内存损坏和内存泄漏

作者:magictong

简介

BSTR的数据结构是什么模样并非本文讨论的问题,但是却是本文的基础。在处理COM的跨平台编程的问题时,需要定义一种通用的字符串类型,它就这样被发明白,而且它的结构很轻易匹配到不同的编程环境中,对于C++程序员来讲,要记着的最基本的一点就是分配BSTR结构时,并非简单的调用new、malloc就能够实现的,而且大部分的字符串相关的API和C库函数也是不能用于处理BSTR的,其实这也是应用BSTR的误区之一,在C++里面,BSTR被简单的define为wchar_t*,这也是轻易引发误解的原因之一。

明天注意讨论一下BSTR作为函数的参数、返回值时,调用者和被调用者操作BSTR时扮演的不同角色问题。首先需要注意的时,在必须应用BSTR时尽量应用BSTR的包装类CComBSTR,它会给你额定实现一些资源的管理工作,令你省力不少,犯错的可能性也就大大降低了。

像一个很简单自然的用法:BSTR bstrInfo = L””,实际上是错误的(当然如果你说我当前就把bstrInfo完全当成wchar_t*来应用,那我无话可说)。对于一个BSTR变量来讲,它只多是NULL或者正确分配的BSTR指针。

BSTR当成参数和返回应用的基本约定

1、[in\out]参数

譬如函数:void GetChangBSTR(BSTR* pbstrTitle),在GetChangBSTR函数外部需要先读取pbstrTitle的值应用,然后改变pbstrTitle的值。

这类情况下被调用者(也就是GetChangBSTR)在给pbstrTitle赋新值前,需要先释放pbstrTitle里面本来的值,然后再给pbstrTitle分配上新的值。

而调用者(也就是调用GetChangBSTR的函数),在传参之前需要先给pbstrTitle赋值上正确的值,调用结束之后还需要再释放pbstrTitle的值。

2、[in]参数

譬如函数:void PutText(BSTR bstrText),在PutText外部仅需读取bstrText的值。

这类情况下被调用者可以随意读取bstrText的值,不需要做其它操作。

而调用者,在传参之前需要先给bstrText赋上正确的值,调用结束后需要释放bstrText的值。

3、[out]参数

譬如函数:void GetText(BSTR* pbstrText),在GetText外部直接给pbstrText赋值。

这类情况下被调用者直接给pbstrText赋值便可,不需要做其它操作。

而调用者,在传参之前不能给pbstrText赋值,调用结束后需要释放pbstrText的值。

4、返回参数

譬如函数:BSTR GetText(),在GetText外部会返回一个BSTR出来。调用者直接返回一个有效的BSTR便可,而调用者需要释放这个返回的BSTR。

BSTR当成参数和返回应用的误区

1、[in\out]参数

这类情况下,被调用者如果没有给参数赋值,不要释放原始值,因为根据约定调用者还会释放一次,这样会造成多次释放,可能致使内存损坏。

void GetChangBSTR(/*[in\out] */BSTR* pbstrTitle)

{

// using the bs here

DoSomething(*pbstrTitle);

if (...)

{

::SysReAllocString(*pbstrTitle, _T("Tecnet"));

}

else

{

::SysFreeString(*pbstrTitle); // 这里的做法是错误的。

}

return;

}

2、[in]参数

被调用者不要对参数停止释放操作,原因和上面相同,调用者还会重复释放一次,可能致使内存损坏。

void PutText(/*[in] */BSTR bstrText)

{

// using the bs here

DoSomething(bstrText);

::SysFreeString(bstrText); // 这里的做法是错误的。

return;

}

3、[out]参数

如果调用者在传参之前给参数赋值,参数传递给被调用者之后,在改变值之前是没有释放操作的,也就是说会有内存泄漏。

void GetText(/*[out] */BSTR* pbstrText)

{

::SysAllocString(*pbstrText, _T("Tecnet"));

return;

}

// use GetText

BSTR bstrText;

::SysAllocString(bstrText, _T("qq"));

GetText(&bstrText);

::SysFreeString(bstrText); // 很可怜,这里实际上只释放了一次

4、返回参数

被调用者不要释放(不管是直接还是直接致使的)返回给调用者的BSTR,因为调用者会释放。

BSTR GetText()

{

BSTR bstrText = ::SysAllocString(bstrText, _T("Tecnet"));

::SysFreeString(bstrText); // 这里释放就喜剧了

return bstrText;

}

// use GetText

BSTR bstrText = GetText(&bstrText);

// use bstrText

DoSome(bstrText); // bstrText已经被释放,应用是有问题的

每日一道理
一个安静的夜晚,我独自一人,有些空虚,有些凄凉。坐在星空下,抬头仰望美丽天空,感觉真实却由虚幻,闪闪烁烁,似乎看来还有些跳动。美的一切总在瞬间,如同“海市蜃楼”般,也只是刹那间的一闪而过,当天空变得明亮,而这星星也早已一同退去……

::SysFreeString(bstrText); // 这就不仅仅是重复释放的问题了

BSTR在类里面应用的误区

1、我想把某个[in]参数BSTR保存到某个类成员变量

这类情况下,直接赋值是不行的,因为表面调用者会释放这个BSTR参数,因此要保存的话,需要类函数自己重新申请一个新的BSTR。

void CSomeClass::SetText(BSTR bs)

{

// m_bstrText是CSomeClass的成员变量

m_bstrText = bs; // 错误做法

m_bstrText = ::SysReAllocString(bs); // 正确做法

}

2、我想传出一个类的BSTR成员变量

同样的道理,因为表面可能在某个时间释放传出的BSTR变量,因此要防止类成员变量被无辜释放,需要生成一个有效的拷贝,再传出。

void CSomeClass::GetText(BSTR& bs)

{

// m_bstrText是CSomeClass的成员变量

bs = m_bstrText; // 错误做法

bs = ::SysAllocString(m_bstrText); // 正确做法

}

BSTR的封装类CComBSTR

微软发明我们应用BSTR有上面的各种不爽,因此决议对其停止封装,很贴心吧!嗯,确实贴心,其中比拟好的一个封装就是CComBSTR(很多项目组可能有自己的BSTR封装,但是其实都是迥然不同的),这个封装类确实很好用(虽然没有供给CString那么多牛皮的功能),应用很方便,但是,如果我们错误应用也会发生噩梦,而且错误很难查找,我们来点评几个(注意:下面的内容需要对CComBSTR封装的基本原理和供给接口有必定了解,但这些并非本文要讨论的内容,另外一个封装类是_bstr_t,它是用引用计数来管理的,实现比CComBSTR复杂很多,个人不太建议应用_bstr_t)。

1、被调用者违背out参数应用约定

void GetText(/*[out]*/BSTR& bstrText)

{

CComBSTR bstrT(_T("qqpcmgr"));

// 错误:bstrT会被自动释放,违背了out参数的应用约定

bstrText = (BSTR)bstrT;

return;

//

// 正确的做法,一般来讲Detach是效率更好的方法

// 但是如果bstrT本身是一个类成员变量,可能要用Copy

bstrText = bstrT.Copy();

bstrText = bstrT.Detach();

return;

}

2、调用者违背out参数应用约定

void GetText(/*[out]*/BSTR& bstrText)

{

// ……

}

// use GetText

CComBSTR bstrText(L"qq");

// 内存泄漏,调用GetText前要先清空bstrText

// bstrText.Empty();

GetText(bstrText);

3、看一个费解一点的

void GetText(/*[out]*/BSTR& bstrText)

{

// ……

}

// use GetText

CComBSTR bstrText;

BSTR bstrInfo = NULL;

GetText(bstrInfo);

// 如果后面没有表现释放bstrInfo

// 这里就会有内存泄漏,这类混用也是比拟危险的

bstrText = bstrInfo;

// 如果你想CComBSTR接管一个BSTR,可以应用

// bstrText.Attach(bstrInfo);

4、重复释放,造成内存损坏

{

CComBSTR bstrText(L"Tencent");

// 因为CComBSTR重载了operator BSTR操作,因此这里是支持的

::SysFreeString(bstrText); // 错误做法,如果你确实想释放,可以调用Empty

}

// 超越bstrText范围,bstrText会被自动释放,可能致使内存损坏

// ……

参考文献

[1] BSTR https://zh.wikipedia.org/zh-cn/BSTR

[2] BSTR_INSIDE http://wenku.baidu.com/view/d577a1c5d5bbfd0a795673b2.html

文章结束给大家分享下程序员的一些笑话语录: 现在社会太数字化了,所以最好是有一个集很多功能于一身的设备!

--------------------------------- 原创文章 By
释放和参数
---------------------------------

转载于:https://www.cnblogs.com/xinyuyuanm/archive/2013/05/30/3108990.html

释放参数BSTR使用误区以及隐藏的内存破坏和内存泄漏相关推荐

  1. mysql8.0最低需要多少内存_MySQL8.0内存相关参数介绍

    本文来自读者投稿 作者:姚远 首先我们给出MySQL内存使用的计算公式: MySQL理论上使用的内存 = 全局共享内存 + max_connections×线程独享内存. 也就是:innodb_buf ...

  2. JVM【带着问题去学习 01】什么是JVM+内存结构+堆内存+堆内存参数(逃逸分析)

    1.是什么 (1) 基本概念:可运行 Java 代码的非真实计算机 ,包括一套字节码指令集.一组寄存器.一个栈.一个垃圾回器,堆和一个存储方法域.它运行在操作系统之上,与硬件没有直接的交互. (2) ...

  3. 内存优化之一——内存优化工具参数详解

    博客结构 1.背景 2.内存查看方式 (1).AS-Profiler (1).运行框-命令行 3.内存参数 (0)PSS (1)Java heap (2)Native Heap (3)Code (4) ...

  4. 二、JVM内存模型及内存参数设置

    二.JVM内存模型 1.Java语言跨平台特性 java程序主要通过JVM来实现跨平台的,JVM编译器将Java源代码文件编译成字节码文件(一次编译,随处运行),然后不同的操作系统生成的机器码不同,但 ...

  5. 清理备用内存/关闭备用内存(备用内存占用过高且不自动释放)

    清理备用内存/关闭备用内存 前言 备用内存介绍 清理备用内存 休眠再唤醒 RAMMap 关闭备用内存 禁用SysMain服务 开启虚拟内存(可忽略) 总结 前言 大家在使用Win7及以上系统时(本文内 ...

  6. mysql8.0最低需要多少内存_MySQL8.0内存相关参数总结

    MySQL理论上使用的内存 = 全局共享内存 + max_connections×线程独享内存. 也就是:innodb_buffer_pool_size + innodb_log_buffer_siz ...

  7. java 启动内存参数_请问该如何设置Java虚拟机JVM启动内存参数?

    jps(JVM Process Status Tool):JVM机进程状况工具 用来查看基于HotSpot JVM里面所有进程的具体状态, 包括进程ID,进程启动的路径等等.与unix上的ps类似,用 ...

  8. python释放变量内存_Python变量内存管理

    一.变量存哪了? x = 10 当我们在p1.py中定义一个变量x = 10,那么计算机把这个变量值10存放在哪里呢了?我们回顾计算机的三大核心组件为:CPU.内存和硬盘.一定不是CPU,那是存放在内 ...

  9. 关于堆内存和栈内存释放

    js 中的内存分为堆内存和 栈内存 堆内存:存储引用类型值 (对象:键值对 函数:代码字符串) 栈内存: 提供JS代码执行的环境和存储基本类型值 堆内存释放 让所有引用堆内存空间地址的变量赋值给Nul ...

最新文章

  1. [深度学习] keras的EarlyStopping使用与技巧
  2. ASMSupport教程4.2
  3. 一个JSON字符串和文件处理的命令行神器jq,windows和linux都可用
  4. ES6/04/严格模式,开启严格模式,严格模式与普通模式对比发生了那些变化,高阶函数,闭包函数,递归函数,递归实例(1,阶乘,2,斐波那契数列,3,根据id返回对应数据对象),浅拷贝和深拷贝
  5. 和dump文件什么区别_将java进程转移到“解剖台”之前,法医都干了什么?
  6. 《Java语言程序设计》(基础篇原书第10版)第十二章复习题答案
  7. 软件管理 --软件仓库的搭建
  8. matlab程序产生OAM波,一种反射型极化转换超表面的轨道角动量产生结构设计的制作方法...
  9. 全球及中国木材干燥窑行业研究及十四五规划分析报告
  10. 低代码技巧:甘特图制作步骤
  11. 售价占激光电视价格一半 抗光幕为何这么贵?
  12. SAE使用以及GPS 的经纬度换算成距离的代码(转载)
  13. 支付宝app支付产品不通过app集成sdk发起支付(附源码)
  14. 性能魔方七剑下天山之莫问剑:全球首创智能评测
  15. ESP32入门基础之UDP和TCP实验
  16. 为什么说华为云WeLink是“最硬核”的协同办公工具?
  17. R语言使用vcd包的assocstats函数计算两个分类变量的相关性的强弱、计算列联表的Phi系数、列联系数和Cramer’s V系数
  18. JVM知识点(全,一篇搞定)
  19. 20210303-CSR
  20. 通用代码生成器,一键生成前端和后端

热门文章

  1. VLAD学习总结和python实现
  2. hd printer lexmark
  3. Swagger——世界上最流行的Api框架
  4. C++ 24点游戏算法
  5. OGG 整理简洁笔记 V
  6. 02 微架构教务系统——课程搜索接口
  7. 10 微架构教务系统——用户登录、注销登录、学生注册接口
  8. 临床预测模型评鉴(PMID: 32350208)
  9. vegas可以做动画吗_使用Vegas如何编辑动漫人物合辑?
  10. 计算机网络定义,分类,OSI基础...