我现在正在赶上当前项目中的C ++ 11/14内容。我无法使用unique_ptr
/ shared_ptr
API函数将资源作为输出参数通过指针返回。
我们以DsGetDcName(..., __out PDOMAIN_CONTROLLER_INFO* ppDCI)
为例。
在c ++ 11之前,有一种广泛使用Windows API的模式。我会有一个RIIA类,它包含PDOMAIN_CONTROLLER_INFO
,在析构函数中调用NetApiBufferFree
,并且有PDOMAIN_CONTROLLER_INFO* operator&()
以便我可以写:
info_ptr spInfo;
DsGetDcName(..., &spInfo);
现在使用C ++ 11/14,我看到很多文章都主张unique_ptr
/ shared_ptr
使用自定义删除器以正确的方式释放资源。当资源作为函数的r值返回时,它确实很有效(LoadLibrary
就是一个很好的例子)。
我发现一个解决方案是在API调用后将原始指针附加到智能指针:
PDOMAIN_CONTROLLER_INFO pDCI = nullptr;
DsGetDcName(..., &pDCI);
std::unique_ptr<DOMAIN_CONTROLLER_INFO, decltype(&NetApiBufferFree)> spInfo(pDCI, &NetApiBufferFree);
然而,这不是我喜欢的方式。据我所知,新的智能指针并非设计用于输出参数,可能是因为“安全第一”的方法。
这里可以做些什么吗?也许某种仿函数类作为参数代理,所以我可以写DsGetDcName(..., &out_param(spInfo))
?
答案 0 :(得分:4)
好吧,你可以创建一个临时包装器,在破坏时初始化你的std::unique_ptr
:
#include <windows.h>
#include <Dsgetdc.h>
#include <Lm.h>
#include <memory>
template<typename T, typename D>
struct OutParameterWrapper
{
OutParameterWrapper(std::unique_ptr<T, D>& Target) : m_Target(Target), m_pSource(nullptr)
{
}
~OutParameterWrapper()
{
m_Target.reset(m_pSource);
}
operator T**()
{
return &m_pSource;
}
std::unique_ptr<T, D>& m_Target;
T* m_pSource;
};
int main(int argc, char** argv)
{
std::unique_ptr<DOMAIN_CONTROLLER_INFO, decltype(&NetApiBufferFree)> spInfo(nullptr, NetApiBufferFree);
DsGetDcName(NULL, NULL, NULL, NULL, 0, OutParameterWrapper<DOMAIN_CONTROLLER_INFO, decltype(&NetApiBufferFree)>(spInfo));
return 0;
}
修改强>
要自动扣除并让它适用于std::unique_ptr
和std::shared_ptr
,您可以执行以下操作:
#include <windows.h>
#include <Dsgetdc.h>
#include <Lm.h>
#pragma comment(lib, "Netapi32.lib")
#include <memory>
template<typename T, typename P>
struct OutParameterWrapper
{
OutParameterWrapper(P& Target) : m_Target(Target), m_pSource(nullptr)
{
}
~OutParameterWrapper()
{
m_Target.reset(m_pSource);
}
operator T**()
{
return &m_pSource;
}
P& m_Target;
T* m_pSource;
};
template<typename P>
OutParameterWrapper<typename P::element_type, P> MakeOutParameterWrapper(P& Target)
{
return OutParameterWrapper<typename P::element_type,P>(Target);
}
int main(int argc, char** argv)
{
std::unique_ptr<DOMAIN_CONTROLLER_INFO, decltype(&NetApiBufferFree)> spInfo(nullptr, NetApiBufferFree);
std::shared_ptr<DOMAIN_CONTROLLER_INFO> spInfo2(nullptr, NetApiBufferFree);
auto nResult = DsGetDcName(NULL, NULL, NULL, NULL, 0, MakeOutParameterWrapper(spInfo));
DsGetDcName(NULL, NULL, NULL, NULL, 0, MakeOutParameterWrapper(spInfo2));
return 0;
}
答案 1 :(得分:0)
到目前为止,我想出了这段代码:
template<typename T>
class out
{
T* _p;
std::shared_ptr<T>& _sp;
public:
out(std::shared_ptr<T>& sp) : _p(nullptr) , _sp(sp) {}
~out() { _sp.reset(_p); }
T** operator&() { _ASSERT(nullptr == _p); return &_p; }
};
但它有两个缺点
GetMeow(&out<Meow>(sp))
而不是GetMeow(&out(sp))
shared_ptr
和unique_ptr
。是否有任何模板忍者?
编辑:
好的,我将Rudolfs的工作与我的一些调整相结合,最终结果如下:https://gist.github.com/kirillkovalenko/8219e7c1afea9b5da5da