載自:http://www.codesky.net/article/200504/63245.htmlhtml
Article last modified on 2002-8-7node
----------------------------------------------------------------app
The information in this article applies to:ide
- C/C++ui
- Microsoft Visual C++ 6.0(SP5)this
----------------------------------------------------------------spa
若是你在程序中這麼聲明:.net
std::list< CComBSTR > list;code
那麼MSVC6.0(SP5)就會產生一個編譯錯誤:orm
f:\program files\microsoft visual studio\vc98\include\list(238) : error C2664: 'destroy' :cannot convert parameter 1 from 'unsigned short ** ' to 'class ATL::CComBSTR *'
Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast
f:\program files\microsoft visual studio\vc98\include\list(235) : while compiling class-template member function 'class std::list<class ATL::CComBSTR,class std::allocator<class ATL::CComBSTR> >::iterator __thiscall std::list<class ATL::CComBSTR,class std::allocator<class ATL::CComBSTR> >::erase(class std::list<class ATL::CComBSTR,class std::allocator<class ATL::CComBSTR> >::iterator)'
錯誤定位於List頭文件的238行:
iterator erase(iterator _P)
{_Nodeptr _S = (_P++)._Mynode();
_Acc::_Next(_Acc::_Prev(_S)) = _Acc::_Next(_S);
_Acc::_Prev(_Acc::_Next(_S)) = _Acc::_Prev(_S);
allocator.destroy(&_Acc::_Value(_S));
_Freenode(_S);
--_Size;
return (_P); }
按照C++標準,能夠存儲在任何容器中的對象都必須有CopyConstructible。
CopyConstructible的一個要求就是,假設t是存儲在容器中的一個類型爲T的對象,那麼&t就返回T*,也就是t的地址。
而ATL的智能包裹類,如CComBSTr、CCOMPtr等,卻都重載了操做符&,CComBSTR類的&操做符返回CComBSTR::m_str,這是一個BSTR類型。這樣就破壞了CopyConstructible的要求。
說到這裏,咱們就不難理解爲何「error C2664: 'destroy' : cannot convert parameter 1 from 'unsigned short ** ' to 'class ATL::CComBSTR *'」了。
這種重載了&操做符的行爲,在與STL聯合使用時,會致使各類各樣的問題(從內存泄漏到隨機崩潰)。
這些危險對象包括有:
CComPtr
CComQIPtr
CComBSTR
_com_ptr_t
千萬不要把它們放入任何STL容器中。固然也要留意其餘重載了operator&的類。
ATL爲咱們提供瞭解決辦法:CAdapt模板類。
這個模板重載了&操做符,再也不讓它返回對象的地址:
// AtlBase.h Line 864
template <class T>
class CAdapt
{
public:
。。。
operator T&()
{
return m_T;
}
operator const T&() const
{
return m_T;
}
T m_T;
};
CAdapt模板的歷史意義就在於此。
這樣咱們就能夠放心大膽地聲明道:
std::vector< CAdapt <CComBSTR> > vect;
typedef vector< CAdapt< CComPtr< IWhatever > > > TWhateverVector;
再也不會有麻煩。
下面的聲明都不會有編譯錯誤:
std::vector<CComBSTR > vecBSTR;
std::vector< CComPtr<IPDH> > vecPDH0;
只有當容器是std::list時,纔會發生編譯錯誤。
並且,實際上使用下面的代碼彷佛也沒有出現問題,好比內存泄漏等:
std::vector<CComBSTR > vec;
vec.push_back(CComBSTR("string"));
對於這種狀況,Igor Tandetnik是這麼說的:
「有時候,你在STL Container中沒有用CAdapt,看上去平安無事。可是,這樣的話,你的代碼就和STL廠商的具體實現密切相關了。從而當你調用之前從沒有用過的容器的某一個方法時,可能會發生一些未定義的事情。因此,Just to be on the safe side,不管什麼時候,當你要把CComBSTR或者其餘重載了operator&的類放入任何STL容器中時,請使用CAdapt。」
本文檔所包含的信息表明了在發佈之日,ZhengYun 對所討論問題的當前見解,Zhengyun 不保證所給信息在發佈之日之後的準確性。
本文檔僅供參考。對本文檔中的信息,Zhengyun 不作任何明示或默示的保證。