Com std::唯一的_ptr和指针到指针

Com std::唯一的_ptr和指针到指针,com,c++11,Com,C++11,我一直在使用std::unique_ptr来存储一些COM资源,并提供了一个自定义的deleter函数。然而,许多COM函数需要指针到指针。现在,我正在编译器中使用_Myptr的实现细节。直接访问此数据成员是否会破坏unique_ptr,或者我是否应该存储大量临时指针以从中构造unique_ptr值?COM对象按其性质可引用计数,因此,除了引用计数智能指针(如ATL::CComPtr或\u com\u ptr\t)之外,您不应该使用任何东西,即使它似乎不适合您的用例(我完全理解您的担忧,我只是认

我一直在使用std::unique_ptr来存储一些COM资源,并提供了一个自定义的deleter函数。然而,许多COM函数需要指针到指针。现在,我正在编译器中使用_Myptr的实现细节。直接访问此数据成员是否会破坏unique_ptr,或者我是否应该存储大量临时指针以从中构造unique_ptr值?

COM对象按其性质可引用计数,因此,除了引用计数智能指针(如
ATL::CComPtr
\u com\u ptr\t
)之外,您不应该使用任何东西,即使它似乎不适合您的用例(我完全理解您的担忧,我只是认为您对它们的重视太多)。这两个类都设计用于使用COM对象时出现的所有有效场景,包括获取指向指针的指针。是的,这是有点太多的功能,但是如果你不期望有任何你不能容忍的负面后果,你应该使用这些类——它们正是为此目的而设计的。

C++0x智能指针有一种可移植的方法来获取原始指针容器.get()或完全使用.release()释放它。您也可以始终使用&(*ptr),但这不太惯用

如果您想使用智能指针来管理对象的生命周期,但仍然需要原始指针来使用不支持智能指针的库(包括标准c库),则可以使用这些函数最方便地获取原始指针

请记住,您仍然需要在希望对象生存的时间内保持智能指针(因此请注意其生存期)

比如:

call_com_function( &my_uniq_ptr.get() ); // will work fine
return &my_localscope_uniq_ptr.get();    // will not
return &my_member_uniq_ptr.get();        // might, if *this will be around for the duration, etc..

注意:这只是对您的问题的一般回答。如何最好地使用COM是一个单独的问题,sharptooth很可能是正确的。

不久前,我不得不解决同样的问题,我提出了两种不同的解决方案:

第一个是一个简单的包装器,它封装了一个“可写”指针,可以是
std::move
d到我的智能指针中。这比使用您提到的临时指针更方便,因为您不能直接在调用站点定义类型

因此,我没有坚持这样做。因此,我所做的是一个
检索
助手函数,它将获取COM函数并返回我的智能指针(并在内部执行所有临时指针操作)。现在,这对于只有一个
T**
参数的自由函数非常有用。如果您想在更复杂的事情上使用它,您可以通过
std::bind
传入调用,并且只保留自由返回的指针

我知道这并不是你要问的问题,但我认为这是解决你问题的好办法

作为补充说明,我更喜欢boost的侵入式_ptr,而不是std::unique_ptr,但这始终是一个品味问题

编辑:以下是使用boost::intrusive\u ptr从我的版本传输过来的一些示例代码(因此它可能无法在使用unique\u ptr时立即运行)

模板
HRESULT检索(T func,std::unique_ptr&ptr)
{
ElementType*raw_ptr=nullptr;
HRESULT result=func(&raw_ptr);
ptr.重置(原始ptr);
返回结果;
}
例如,它可以这样使用:

std::unique_ptr<IFileDialog, ComDeleter> FileDialog;
/*...*/
using std::bind;
using namespace std::placeholders;
std::unique_ptr<IShellItem, ComDeleter> ShellItem;
HRESULT status = retrieve(bind(&IFileDialog::GetResult, FileDialog, _1), ShellItem);
std::unique_ptr FileDialog;
/*...*/
使用std::bind;
使用名称空间std::占位符;
std::唯一的外壳项目;
HRESULT status=retrieve(绑定(&IFileDialog::GetResult,FileDialog,_1),ShellItem);

对于奖励积分,您甚至可以让
检索
返回唯一的\u ptr,而不是通过引用获取。
bind
生成的函子应该有签名typedefs来派生指针类型。然后,如果得到错误的
HRESULT

则可以抛出异常。请使用以下帮助函数

template< class T >
T*& getPointerRef ( std::unique_ptr<T> & ptr )
{
    struct Twin : public std::unique_ptr<T>::_Mybase {};
    Twin * twin = (Twin*)( &ptr );
    return twin->_Myptr;
}
模板
T*&getPointerRef(标准::唯一的ptr&ptr)
{
struct Twin:public std::unique_ptr::_Mybase{};
双*双=(双*)(&ptr);
返回twin->U Myptr;
}
检查执行情况

int wmain ( int argc, wchar_t argv[] )
{   
    std::unique_ptr<char> charPtr ( new char[25] );
    delete getPointerRef(charPtr);
    getPointerRef(charPtr) = 0;

    return charPtr.get() != 0;
}
intwmain(intargc,wchar\t argv[])
{   
std::unique_ptr charPtr(新字符[25]);
删除getPointerRef(charPtr);
getPointerRef(charPtr)=0;
return charPtr.get()!=0;
}

为什么不使用
ATL::CComPtr
\u com\u ptr\t
?@sharptooth:我的应用程序只保存一个引用。没有必要为我的一个引用计算引用数。@DeadMG:没问题,但是您不知道的其他COM对象可能会持有该对象并希望共享所有权。你不能把“我想我是唯一一个拿着指针的人”和COM对象结合起来,因为它们都是为支持引用计数而设计的。我的观点是,即使你不需要引用计数,你也必须使用它。@sharptooth:你误读了我。我只有一份推荐信。其他参考资料仍全部统计在内。这只是COM对象——使用DirectX。你完全误解了这个问题。我需要一个指向
unique\u ptr
中内部指针的指针,而不仅仅是值。unique\u ptr不提供直接访问内部指针的方法,因为这样做会非常不安全。智能指针的目的是为了安全。COM对象无论如何都是引用计数的,所以不管您喜欢与否,您所做的任何事情都将是一个冗余的包装器。unique_ptr并不是为这个目的而设计的,所以任何试图将其加入的尝试都会增加不必要的复杂性和出错的机会。CComPtr没有开销。就用这个吧。我刚刚注意到你
删除了你
新的[]
int wmain ( int argc, wchar_t argv[] )
{   
    std::unique_ptr<char> charPtr ( new char[25] );
    delete getPointerRef(charPtr);
    getPointerRef(charPtr) = 0;

    return charPtr.get() != 0;
}