zoukankan      html  css  js  c++  java
  • ATL 复制策略和CAdapt

    http://msdn.microsoft.com/zh-cn/library/cc468023(VS.71).aspx

    template <class T>
    class _Copy
    {
    public:
        static HRESULT copy(_Out_ T* p1, _In_ const T* p2) 
        { 
            Checked::memcpy_s(p1, sizeof(T), p2, sizeof(T)); 
            return S_OK;
        }
        static void init(_Inout_opt_ T*) 
        {
        }
        static void destroy(_Inout_opt_ T*) 
        {
        }
    };
    
    template<>
    class _Copy<VARIANT>
    {
    public:
        static HRESULT copy(_Out_ VARIANT* p1, _In_ const VARIANT* p2) 
        {
            p1->vt = VT_EMPTY; 
            return VariantCopy(p1, const_cast<VARIANT*>(p2));
        }
        static void init(_Inout_ VARIANT* p) 
        {
            p->vt = VT_EMPTY;
        }
        static void destroy(_Inout_ VARIANT* p) 
        {
            VariantClear(p);
        }
    };
    

    不同类型之间

        template <>
        class GenericCopy<VARIANT, BSTR>
        {
        public :
            typedef VARIANT    destination_type;
            typedef BSTR    source_type;
    
            static void init(destination_type* p)
            {
                GenericCopy<destination_type>::init(p);
            }
            static void destroy(destination_type* p)
            {
                GenericCopy<destination_type>::destroy(p);
            }
            static HRESULT copy(destination_type* pTo, const source_type* pFrom)
            {
                return CComVariant(*pFrom).Detach(pTo);
            }
    
        }; // class GenericCopy<VARIANT, BSTR>
    

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

    http://www.codesky.net/article/doc/200504/2005042719582649.htm

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

    Written by zhengyun@tomosoft.com

  • 相关阅读:
    Magento2 观察者模式 之 插件
    Magento2 自定义生成日志函数
    magento 由于Httpd进程增多,导致CPU占用100%问题
    Magento composer 安装
    htaccess 的使用基本小节 For apache httpd
    设计便捷命令行工具列表
    docker-lnmp dockerfile
    使用Portainer管理Docker
    关于IIS站点最大并发量分析
    深入理解IIS的多线程工作机制
  • 原文地址:https://www.cnblogs.com/Clingingboy/p/2080077.html
Copyright © 2011-2022 走看看