boost :: multi_index_container与_com_ptr_t对象崩溃

时间:2017-11-21 15:06:42

标签: c++ boost

我尝试将boost::multi_index_container与_com_ptr_t对象一起使用。 代码编译时没有警告但在运行时崩溃。 标准容器(std::setmap等)与这些对象完美配合。

是否可以将multi_index_container与_com_ptr_t?

一起使用

示例代码:

#include "stdafx.h"
#include <boost\multi_index_container.hpp>
#include <boost\multi_index\random_access_index.hpp>
#include <boost\multi_index\global_fun.hpp>
#include <boost\multi_index\ordered_index.hpp>

#import "C:\Windows\SysWOW64\msxml6.dll" exclude("ISequentialStream", "_FILETIME")

using CTest = 
  boost::multi_index_container<MSXML2::IXMLDOMDocument2Ptr, 
    boost::multi_index::indexed_by<boost::multi_index::random_access<>>>;


int main()
{
    ::CoInitialize(nullptr);

    CTest tst;

    MSXML2::IXMLDOMDocumentPtr doc;
    doc.CreateInstance(CLSID_DOMDocument);

    tst.push_back(std::move(doc)); <-- crash here

    ::CoUninitialize();

    return 0;
}

1 个答案:

答案 0 :(得分:2)

  • 我注意到您定义的multi_index_container保存了MSXML2::IXMLDOMDocument2Ptr类型的指针,但doc的类型为MSXML2::IXMLDOMDocumentPtr(没有2)。我认为这是可以的,因为问题与这种差异无关。
  • Boost.MultiIndex does support move semantics,因此您可以随意使用std::move
  • 实际问题是_com_ptr_t有一个奇怪的,破坏性的operator& overload返回指向包装界面的指针。这会混淆Boost.MultiIndex的内部代码。您可以按如下方式轻松绕过此重载:

#include <boost\multi_index_container.hpp>
#include <boost\multi_index\random_access_index.hpp>
#include <boost\multi_index\global_fun.hpp>
#include <boost\multi_index\ordered_index.hpp>

#import "C:\Windows\SysWOW64\msxml6.dll" exclude("ISequentialStream", "_FILETIME")

struct IXMLDOMDocument2Ptr:MSXML2::IXMLDOMDocument2Ptr
{
  using MSXML2::IXMLDOMDocument2Ptr::IXMLDOMDocument2Ptr;

  IXMLDOMDocument2Ptr* operator&(){return this;}
  const IXMLDOMDocument2Ptr* operator&()const{return this;}
};

using CTest = 
  boost::multi_index_container<IXMLDOMDocument2Ptr, 
    boost::multi_index::indexed_by<boost::multi_index::random_access<>>>;

int main()
{
    ::CoInitialize(nullptr);
    {
        // defined in scope so that destruction happens before CoUninitialize
        CTest tst; 

        MSXML2::IXMLDOMDocumentPtr doc;
        doc.CreateInstance(CLSID_DOMDocument);

        tst.push_back(std::move(doc));
    }
    ::CoUninitialize();

    return 0;
}
  • 你介意在Boost Trac输入这个问题的票吗?我可以在内部解决问题(不依赖于用户可重载的operator&),但是我需要一段时间才能找到时间,我不想忘记它。

<强>后记

如果您在整个程序中遇到此问题,可以按如下方式自动执行修复:

#include <boost\multi_index_container.hpp>
#include <boost\multi_index\random_access_index.hpp>
#include <boost\multi_index\global_fun.hpp>
#include <boost\multi_index\ordered_index.hpp>

#import "C:\Windows\SysWOW64\msxml6.dll" exclude("ISequentialStream", "_FILETIME")

template<typename CComPtr>
struct CFixedAddressofComPtr:CComPtr
{
  using CComPtr::CComPtr;

  CFixedAddressofComPtr* operator&(){return this;}
  const CFixedAddressofComPtr* operator&()const{return this;}
};

template<typename CComPtr,typename TIndexList>
using CComPtrMultiIndexContainer=boost::multi_index_container<
  CFixedAddressofComPtr<CComPtr>,
  TIndexList
>;

using CTest = 
  CComPtrMultiIndexContainer<MSXML2::IXMLDOMDocument2Ptr, 
    boost::multi_index::indexed_by<boost::multi_index::random_access<>>>;

int main()
{
    ::CoInitialize(nullptr);

    {
        // declared in scope so that destruction happens before CoUninitialize.
        CTest tst; 

        MSXML2::IXMLDOMDocumentPtr doc;
        doc.CreateInstance(CLSID_DOMDocument);

        tst.push_back(std::move(doc));
    }

    ::CoUninitialize();

    return 0;
}