如果你用C++來編寫COM,那么你將必不可少的使用這三個類型。使用這三種wrapper
class毫無疑問會簡化我們的編程,使得使用SAFEARRAY,
VARIANT和BSTR簡單。但是,使用這三個類型依然需要小心,因為使用不當的話,就會造成內存泄漏,或效率降低。
1. 如果拷貝兩個BSTR
假如我們一個BSTR,這個時候我希望復制一份BSTR,并丟棄之前的BSTR。通常我們會這么寫:
CComBSTR StringToBSTR(const string & sVal)
{
CComBSTR bstrValue = sVal.data();
return bstrValue;
}
int main()
{
CComBSTR vValue = StringToBSTR("value");
return 0;
}
當然,上面這個程序沒有任何問題,不會有任何內存泄漏的可能。但是,你有沒有上面代碼里都發生了什么了?
答案很簡單,在函數StringToBSTR里面,講bstrValue返回的時候,會調用CComBSTR::Copy(),在Copy()里面將會調用
::SysAllocStringByteLen()
這個函數。而后在給vValue賦值的時候,又 會調用一次
::SysAllocString()
顯而易見,開銷很大。
那么,我們將怎么改進這段代碼了?
BSTR StringToBSTR(const string & sVal)
{
CComBSTR bstrValue = sVal.data();
return bstrValue.Detach();
}
int main()
{
CComBSTR vValue.Attach(StringToBSTR("value"));
return 0;
}
這樣,通過CComBSTR::Detach(),我們將BSTR返回回來,通過CComBSTR::Attach(),我們將BSTR指針存儲起來。這樣,就減小了兩次開銷,大大提高了效率,也不會造成內存效率。
2. 如何使用CComSafeArray
使
用CComSafeArray的一個最大的好處,就是它會自動釋放元素是VARIANT和BSTR。也就是說,如果你的類型是VARIANT,它會自動調
用::VariantClear()。如果你的類型是BSTR,他會自動調用::SysStringFree()方法。但是使用它的時候,同樣要小心。
2.1 成對使用::SafeArrayAccessData()和::SafeArrayUnaccessData()
我們有時候會這樣使用CComSafeArray的元素:
void DoSomething()
{
CComSafeArray<double> pSafeArray(3);
double * pVal = NULL;
::SafeArrayAccessData(pSafeArray.m_psa, (void**)&pVal);
//handle the elements through the pVal;
}
因為::SafeArrayAccessData
方法會在SFAEARRAY上給lock加1. 如果上面程序顯示調用CComSafeArray::Destroy()函數,你檢查它返回來的HRESULT的時候,應該是下面的值:
hr 0x8002000d 內存已鎖定。 HRESULT
如果你不仔細檢查,那么將造成CComSafeArray沒有釋放。
2.2 從CComSafeArray轉為成CComVariant
有時候我們使用CComVariant包裝SAFEARRY。你會這樣寫代碼:
void DoSomething()
{
CComSafeArray<double> pSafeArray(3);
//fill the safearray
CComVariant v = pSafeArray.Detach();
}
你可能會任務CComVariant會存儲pSafeArray的指針。可惜,你錯了。
CComVariant會調用::SafeArrayCopy
來完成賦值操作。而你的pSafeArray已經調用了Detach()操作,那么它里面的SAFEARRAY就變成了孤兒,沒有人去釋放它了。
那么你應該怎么寫了?
你可以這么寫:
void DoSomething()
{
CComSafeArray<double> pSafeArray(3);
//fill the safearray
CComVariant v = pSafeArray.m_psa;
}
這樣,CComVariant會調用::SafeArrayCopy
來完成復制操作,而CComSafeArray也會保證在析構的時候釋放里面的SAFEARRAY。
使用上面三個wrapper類,確實可以很方便我們編程,也能避免很多memory leak。但是,使用他們同樣要小心,不然,同樣會造成性能損失,或者,更糟糕的,內存泄漏。