CComBSTR会自动管理字符串的内存空间,在析构时释放空间。由于C++对象在出其作用域时会进行析构。所以有一些情形下,使用CComBSTR容易犯下错误。
来看以下代码:
BSTR bstr1 = CComBSTR(L"hello"); BSTR bstr2 = CComBSTR(L"world"); TRACE(L"%s, %s\n", bstr1, bstr2);
本来可能预期输出的hello, world
而实际输出是world, world
这是因为在赋值语句完成之后,CComBSTR(L”hello”)就析构了释放了空间,bstr1指向了这块被释放的内存。在随后的赋值语句中,CComBSTR(L”world”)又利用了这块内存。然后bstr1和bstr2就指向了同一块内存。
修改代码如下:
BSTR bstr1 = CComBSTR(L"hello"); BSTR bstr2 = CComBSTR(L"world"); TRACE(L"%s, %s\n", bstr1, bstr2); TRACE(L"bstr1[%x] %s\n", bstr1, bstr1); TRACE(L"bstr2[%x] %s\n", bstr2, bstr2);
输出结果为:
world, world
bstr1[6f8b94] world
bstr2[6f8b94] world
从其汇编码也可以看出:
BSTR bstr1 = CComBSTR(L"hello"); 011B76D2 mov eax,120DDB0h 011B76D7 test eax,eax 011B76D9 jne testBSTR+44h (11B76E4h) 011B76DB mov dword ptr [ebp-38h],0 011B76E2 jmp testBSTR+75h (11B7715h) 011B76E4 mov esi,esp 011B76E6 push 120DDB0h 011B76EB call dword ptr [__imp__SysAllocString@4 (16EF3DCh)] 011B76F1 cmp esi,esp 011B76F3 call _RTC_CheckEsp (11F1FF0h) 011B76F8 mov dword ptr [ebp-38h],eax 011B76FB xor ecx,ecx 011B76FD cmp dword ptr [ebp-38h],0 011B7701 sete cl 011B7704 movzx edx,cl 011B7707 test edx,edx 011B7709 je testBSTR+75h (11B7715h) 011B770B push 8007000Eh 011B7710 call ATL::AtlThrowImpl (11B1109h) 011B7715 lea eax,[ebp-38h] 011B7718 mov dword ptr [ebp-88h],eax 011B771E mov ecx,dword ptr [ebp-88h] 011B7724 mov edx,dword ptr [ecx] 011B7726 mov dword ptr [bstr1],edx 011B7729 mov esi,esp 011B772B mov eax,dword ptr [ebp-38h] 011B772E push eax 011B772F call dword ptr [__imp__SysFreeString@4 (16EF3D8h)] 011B7735 cmp esi,esp 011B7737 call _RTC_CheckEsp (11F1FF0h) BSTR bstr2 = CComBSTR(L"world");
在bstr2赋值语句之前就已经调用__imp_SysFreeString释放空间了。
解决办法是将CComBSTR作用域加大,比如构造作用域在函数范围内的两个变量str1和str2。
代码如下:
CComBSTR str1(L"hello"); CComBSTR str2(L"world"); TRACE(L"%s, %s\n", str1, str2); TRACE(L"str1[%x] %s\n", str1, str1); TRACE(L"str2[%x] %s\n", str2, str2);
输出结果如下:
hello, world
str1[107bd5c] hello
str2[107bd34] world
从反汇编可以看出__imp__SysFreeString是在函数退出后调用。
结论:
在使用CComBSTR时,尽量不要做复杂操作,而且不要让其出现在等号右边。CA2T之类的也是。MSDN上说的比较详细,还有关于CComBSTR导致内存泄露的,具体参见MSDN。
原文:http://www.cnblogs.com/shokey520/p/3885421.html