STL Container和ATL智能包裹類的衝突

STL Container和ATL智能包裹類的衝突

載自: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); }

緣由:重載operator&的行爲破壞了CopyConstructible

按照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&的類。

解決辦法:使用CAdapt模板類

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 不作任何明示或默示的保證。

相關文章
相關標籤/搜索