STL Container和ATL智能包裹类的冲突

载自:http://www.codesky.net/article/200504/63245.html

Article last modified on 2002-8-7

----------------------------------------------------------------

The information in this article applies to:

-          C/C++

-          Microsoft Visual C++ 6.0(SP5)

----------------------------------------------------------------

现象:编译错误

如果你在程序中这么声明:

std::list< CComBSTR > list;

那么MSVC6.0(SP5)就会产生一个编译错误:

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

STL Container和ATL智能包裹类的冲突的更多相关文章

  1. 智能指针类模板(上)——STL中的智能指针

    智能指针类模板智能指针本质上就是一个对象,它可以像原生指针那样来使用. 智能指针的意义-现代C++开发库中最重要的类模板之一-C++中自动内存管理的主要手段-能够在很大程度上避开内存相关的问题 1.内 ...

  2. C++中的智能指针类模板

    1,智能指针本质上是一个对象,这个对象可以像原生的指针一样使用,因为智能指 针相关的类通过重载的技术将指针相关的操作符都进行了重载,所以智能指针对象可以像原生指针一样操作,今天学习智能指针类模板,通过 ...

  3. c/c++ 模板与STL小例子系列<二> 模板类与友元函数

    c/c++ 模板与STL小例子系列 模板类与友元函数 比如某个类是个模板类D,有个需求是需要重载D的operator<<函数,这时就需要用到友元. 实现这样的友元需要3个必要步骤 1,在模 ...

  4. Android中View类OnClickListener和DialogInterface类OnClickListener冲突解决办法

    Android中View类OnClickListener和DialogInterface类OnClickListener冲突解决办法 如下面所示,同时导入这两个,会提示其中一个与另一个产生冲突. 1i ...

  5. Maven类包冲突终极解决方案

    本文转自:http://ian.wang/106.htm 举例A依赖于B及C,而B又依赖于X.Y,而C依赖于X.M,则A除引B及C的依赖包下,还会引入X,Y,M的依赖包(一般情况下了,Maven可通过 ...

  6. Maven类包冲突终极三大解决技巧 mvn dependency:tree

    Maven对于新手来说是<步步惊心>,因为它包罗万象,博大精深,因为当你初来乍到时,你就像一个进入森林的陌生访客一样迷茫. Maven对于老手来说是<真爱配方>,因为它无所不能 ...

  7. [转]Maven类包冲突终极三大解决技巧

    举例 A依赖于B及C,而B又依赖于X.Y,而C依赖于X.M,则A除引B及C的依赖包下,还会引入X,Y,M的依赖包(一般情况下了,Maven可通过<scope>等若干种方式控制传递依赖).这 ...

  8. 记一次多个Java Agent同时使用的类增强冲突问题及分析

    摘要:Java Agent技术常被用于加载class文件之前进行拦截并修改字节码,以实现对Java应用的无侵入式增强. 本文分享自华为云社区<记一次多个JavaAgent同时使用的类增强冲突问题 ...

  9. 问题解决——在STL的queue中使用自定义类

    本文原创,转载请保证文章的完整性,并显要的注明出处. 本文链接:http://blog.csdn.net/wlsgzl/article/details/38843513 平时很少用STL,就算用,也基 ...

随机推荐

  1. Codeforces Round #245 (Div. 1) 429D - Tricky Function 最近点对

    D. Tricky Function Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 codeforces.com/problemset/problem/42 ...

  2. 推荐资料——最受网友力荐的30份HTML前端开发资料

    w3cmark最近会新增一个栏目,专注于搜集前端资源的下载,包括和前端相关的电子书.文档PPT.手册.视频教程等等.而下载的媒介是用微博的微盘,至于为什么选择微盘的,那是因为和微博关联起来,通过微盘上 ...

  3. C++进制转换(十进制转二进制、八进制、随意进制)

    十进制转二进制: //十进制转二进制 #include<iostream> using namespace std; void printbinary(const unsigned int ...

  4. cocos2d-x 3.1.1 学习笔记[3]Action 动作

    这些动画貌似都非常多的样子,就所有都创建一次. 代码例如以下: /* 动画*/ auto sp = Sprite::create("card_bg_big_26.jpg"); Si ...

  5. [Angular 2] ElementRef, @ViewChild & Renderer

    ElementRef: In Angular2 Doc, it suggest to "avoid" using ElementRef. It access DOM directl ...

  6. SQL Server如何截断(Truncate)和收缩(Shrink)事务日志

    当SQL Server截断事务日志时,它仅仅是在虚拟日志文件中做个标记,以便不再使用它,然后准备以重用形式来做备份(假如运载在完整或是批量日志恢复模型).也就是说,在使用简单恢复模型时,事务日志包括如 ...

  7. linux下的十六进制编辑器---wxHexEdit

    ....其实wxHexEdit是一个跨平台的十六进制编辑器,支持windows,linux,mac. 之所以标题用linux...是因为windows下多数都用winhex,UE之类的编辑器,而lin ...

  8. __attribute__((unused))

    在gcc手册中找到了有关的解释: unused:This attribute, attached to a function, means that the function is meant to ...

  9. C#基础--局部类型Partial

    局部类型 原本来在同一个命名(namespace)空间下  是不允许相同的类(class)名存在的  但是partial关键字可以允许在同一个namespace下有想通过的类名存在 写法 下面的两个不 ...

  10. Android 高级UI设计笔记14:Gallery(画廊控件)之 3D图片浏览

    1. 利用Gallery组件实现 3D图片浏览器的功能,如下: 2. 下面是详细的实现过程如下: (1)这里我是测试性代码,我的图片是自己添加到res/drawable/目录下的,如下: 但是开发中不 ...