CComBSTR的生命期
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。
It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity. We had everything before us, we had nothing before us.
这是最好的时代,这是最坏的时代;这是智慧的年代,这是愚蠢的年代;这是信仰的时期,这是怀疑的时期;我们的前途拥有一切,我们的前途一无所有。
这是最好的时代,这是最坏的时代;这是智慧的年代,这是愚蠢的年代;这是信仰的时期,这是怀疑的时期;我们的前途拥有一切,我们的前途一无所有。