对于《可恶的BSTR。。》再开一贴以吸引大家的注意

libinfei8848 2010-08-09 11:23:16
前几天曾开一贴:
《可恶的BSTR和它娘家人们》
http://blog.csdn.net/libinfei8848/archive/2010/08/06/5794318.aspx
首先要感谢几位大侠的指点,后来在分析了代码发现这样的问题:

_bstr_t wsClauseForLink(L"MASTEROBJID='");
//pDevObjID是有值的BSTR变量
wsClauseForLink += pDevObjID; //(1)
wsClauseForLink += L"' OR SLAVEROBJID='";
wsClauseForLink += pDevObjID; //(2)
wsClauseForLink += L"'";

pDevObjID变量是我调用一位同事的接口方法得到的。因为他是我的领导,比较有权威。所以我一开始就没有怀疑大哥。。最后无奈的情况下找他要了代码跟了进去发现:

STDMETHODIMP
CPText::get_ObjectID( BSTR* Value)
{
....//省略实现部分
*Value = (_bstr_t)val.bstrVal;
return S_OK;
}

他返回的是一个局部变量的值,所以在我调用的时候出现问题。
但是。。。。我今天要说的不是来当着大庭广众来数落我的领导,或者来证明自己没有错。
我是想说。。。额,BSTR还是让我感觉力不从心。。。
首先,微软为了提高COM架构的效率,系统对于BSTR提供了内存的特殊处理。即:sysfreestring的时候只是标记了bstr内存为可再分配内存,而内存里面的内容实际上没有destory掉。而这正是我纠结的根本之所在.
正常情况下,加入返回一个局部变量对象,它会在返回的时候调用其析构函数,然后回收内存:

Object& GetObject(Object& Other)
{
Object tmp = Other;
return tmp;
}

那么我们调用这个方法的时候会第一时间认知到这个错误:

Object &lOne = GetObject(lOther);
lOne.get_XXX(xxx);//这一步必定是走不下去了,在调试的瞟一眼马上就能大喊:XX这是你的问题咯。。。


好来说说BSTR的问题:
	
pObject->get_ObjectID(&pDevObjID);
wsClauseForTopo += pDevObjID;
wsClauseForTopo += pDevObjID; //(1)
wsClauseForTopo += pDevObjID; //(2)
wsClauseForTopo += pDevObjID; //(3)
wsClauseForTopo += pDevObjID; //(4)

好根据BSTR的内存优化原理,执行到(1)的时候,我们总是幸运的,虽然内存已标记可重分配,但是地址还有效,值也有效。那么它心安理得的走了下去,执行到(2)通常也会人品爆发,那继续走吧,执行到(3)如果还没有问题,到了(4)甚至是一路坦荡荡那就可以去买彩票了。。。
pDevObjID这个局部变量返回的内存总会有重分配的时候,而这种BUG的出现会飘忽不定的。。。以至于我总是难以想到是调用的别人的代码而造成,翻来覆去的查看代码。。。
不知不觉中,又让我增长了debug的经验。。。。
欢迎砸砖。。。。(据说csdn大佬们分给的不多是没人愿意给回帖的,所以今天我挥泪割肉了。。。)
...全文
314 30 打赏 收藏 转发到动态 举报
写回复
用AI写文章
30 条回复
切换为时间正序
请发表友善的回复…
发表回复
hufeikong 2010-08-13
  • 打赏
  • 举报
回复
不知不觉中,也让我增长了debug的经验
libinfei8848 2010-08-12
  • 打赏
  • 举报
回复
大家都来集思广益吧,我准备结贴了。。
libinfei8848 2010-08-12
  • 打赏
  • 举报
回复
[Quote=引用 23 楼 csdmadmimistrator 的回复:]

vector用过不?vector
vector<int> vec;
.......
int * pItem = vec[100];
当你删除vec的元素让它的元素个数少于100个的时候,你访问pItem依然不会crash,只要之间没有引起vec内部重新分配内存
[/Quote]

vector也是作者有意的一些行为,比如预分配之类的,当然不会crash掉了,而不是编译器行为。
眼睛猥琐男 2010-08-12
  • 打赏
  • 举报
回复
地球本来就是不安全的,只能自己小心点吧
CSDMAdmimistrator 2010-08-12
  • 打赏
  • 举报
回复
[Quote=引用 22 楼 olncy 的回复:]
首先,微软为了提高COM架构的效率,系统对于BSTR提供了内存的特殊处理。即:sysfreestring的时候只是标记了bstr内存为可再分配内存,而内存里面的内容实际上没有destory掉。而这正是我纠结的根本之所在.
[/Quote]
别啥事情都赖到BSTR头上.....
内存池用过不?
这跟BSTR没有任何必然联系,BSTR同样可以指向new出来的内存
这里是因为bstr用了SysAllocString来分配内存
SysFreeString 是从windows内部维护的内存池里面申请内存的,当你调用SysFreeString的时候,就只是标记这块内存可用,而不返回给系统,这是内存池的基本用法....

[Quote=引用 22 楼 olncy 的回复:]
正常情况下,加入返回一个局部变量对象,它会在返回的时候调用其析构函数,然后回收内存:
[/Quote]
vector用过不?vector
vector<int> vec;
.......
int * pItem = vec[100];
当你删除vec的元素让它的元素个数少于100个的时候,你访问pItem依然不会crash,只要之间没有引起vec内部重新分配内存
olncy 2010-08-12
  • 打赏
  • 举报
回复
万恶的bstr。因为微软对bstr有多种封装,用起来还是要小心一些,反正用之前我都会看一次定义才用的。
ayw215 2010-08-12
  • 打赏
  • 举报
回复
不懂
lvshaoqing 2010-08-12
  • 打赏
  • 举报
回复
typedef WCHAR OLECHAR;
typedef /* [wire_marshal] */ OLECHAR *BSTR;

BSTR 这个有什么好讨论的。

class _bstr_t {
public:
// Constructors
//
_bstr_t() throw();
_bstr_t(const _bstr_t& s) throw();
_bstr_t(const char* s) ;
_bstr_t(const wchar_t* s) ;
_bstr_t(const _variant_t& var) ;
_bstr_t(BSTR bstr, bool fCopy) ;
...
}
这玩意还有点点意思。 不过夜就那样。 呵呵。
pfcz_myp 2010-08-12
  • 打赏
  • 举报
回复
说实话,不知不觉中,也让我增长了debug的经验。。。。
qiuqingpo 2010-08-12
  • 打赏
  • 举报
回复
也让我增加了DEBUG经验
poiu10000 2010-08-11
  • 打赏
  • 举报
回复
灌水中。。。。。
libinfei8848 2010-08-11
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 redleaves 的回复:]

>首先,微软为了提高COM架构的效率,系统对于BSTR提供了内存的特殊处理。即:sysfreestring的时候只是标记了bstr内存为可再分配内存,而内存里面的内容实际上没有destory掉。而这正是我纠结的根本之所在.

以上内容应该是楼主推断而来的吧?事实上,所有的堆/栈分配的行为都可能引起主所遇到的问题.并不是"优化"才会引起的.而且,似乎没有听说哪里有指出过,BSTR有楼主所言的优……
[/Quote]

给你个msdn的地址吧:
http://msdn.microsoft.com/en-us/library/ms221105.aspx
libinfei8848 2010-08-11
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 redleaves 的回复:]

>首先,微软为了提高COM架构的效率,系统对于BSTR提供了内存的特殊处理。即:sysfreestring的时候只是标记了bstr内存为可再分配内存,而内存里面的内容实际上没有destory掉。而这正是我纠结的根本之所在.

以上内容应该是楼主推断而来的吧?事实上,所有的堆/栈分配的行为都可能引起主所遇到的问题.并不是"优化"才会引起的.而且,似乎没有听说哪里有指出过,BSTR有楼主所言的优……
[/Quote]

这样我给你一段原文的翻译你看看:
 ●Automation会cache BSTR使用的空间,以提高SysAllocString/SysFreeString 的性能,会给测试发现问题带来困难。如果可能推荐在调试时使用Compuware DevPartner 7.x及更高版本的工具。
而这个cache就是文中我提到的一种优化。或者我称之为优化是不专业的,如果给你带来困扰请见谅
libinfei8848 2010-08-11
  • 打赏
  • 举报
回复
[Quote=引用 15 楼 woailp___2005 的回复:]

分应该给我这样的人嘛~~
[/Quote]

你再多说两句,我就开始给分咯
  • 打赏
  • 举报
回复
 STDMETHODIMP 
CPText::get_ObjectID( BSTR* Value)
{
....//省略实现部分
*Value = (_bstr_t)val.bstrVal;
return S_OK;
}


一般这里都用_bstr_t::copy
STDMETHODIMP CAlertMsg::get_ConnectionStr(BSTR *pVal){ //  m_bsConStr is _bstr_t
*pVal = m_bsConStr.copy();
}


jackyjkchen 2010-08-11
  • 打赏
  • 举报
回复
不用com的路过
Q446512799 2010-08-11
  • 打赏
  • 举报
回复
分应该给我这样的人嘛~~
redleaves 2010-08-11
  • 打赏
  • 举报
回复
[Quote=引用 11 楼 libinfei8848 的回复:]
而这个cache就是文中我提到的一种优化。或者我称之为优化是不专业的,如果给你带来困扰请见谅
[/Quote]呵呵.你在上文里对"优化"的说明是"而内存里面的内容实际上没有destory掉。"而我的回复是针对这个行为.因为基本上所有的stack/heap的内存块释放时,都不会刻意"destroy"其中的内容..
redleaves 2010-08-10
  • 打赏
  • 举报
回复
>首先,微软为了提高COM架构的效率,系统对于BSTR提供了内存的特殊处理。即:sysfreestring的时候只是标记了bstr内存为可再分配内存,而内存里面的内容实际上没有destory掉。而这正是我纠结的根本之所在.

以上内容应该是楼主推断而来的吧?事实上,所有的堆/栈分配的行为都可能引起主所遇到的问题.并不是"优化"才会引起的.而且,似乎没有听说哪里有指出过,BSTR有楼主所言的优化行为.
BSTR只是有个长度标记,在C/C++中引用需要跳过这个标记而已.所以才会有专门的分配/释放等函数.其它的应该和一般的内存处理行为是一致的吧.
sxdkxgwan 2010-08-10
  • 打赏
  • 举报
回复
我来想各位大哥学习。。。
加载更多回复(8)

64,649

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧