C++11 采用共享\u ptr和唯一\u ptr的函数的代码复制
问题: 让我们假设我有一个算法,它将一个唯一的\u ptr用于某种类型:C++11 采用共享\u ptr和唯一\u ptr的函数的代码复制,c++11,parameters,smart-pointers,code-duplication,C++11,Parameters,Smart Pointers,Code Duplication,问题: 让我们假设我有一个算法,它将一个唯一的\u ptr用于某种类型: void FancyAlgo(unique_ptr<SomeType>& ptr); 当我需要用unique_ptr调用它时: FancyAlgo(*ptr); 同样,对于共享ptr 1、这是生产代码中可以接受的风格吗?(我在某个地方看到,在智能指针的上下文中,不应该以类似的方式操作原始指针。它有引入神秘bug的危险。) 2,如果1不是一个好主意,你能提出更好的方法(没有代码重复)吗 谢谢。智能指针
void FancyAlgo(unique_ptr<SomeType>& ptr);
当我需要用unique_ptr调用它时:
FancyAlgo(*ptr);
同样,对于共享ptr
1、这是生产代码中可以接受的风格吗?(我在某个地方看到,在智能指针的上下文中,不应该以类似的方式操作原始指针。它有引入神秘bug的危险。)
2,如果1不是一个好主意,你能提出更好的方法(没有代码重复)吗
谢谢。智能指针是关于所有权的。请求智能指针就是请求所有权信息或控制权 请求对智能指针的非常量左值引用就是请求更改该值的所有权状态的权限 请求对智能指针的常量左值引用就是请求查询该值的所有权状态的权限 请求对智能指针的右值引用就是一个“接收器”,并承诺从调用者那里夺走所有权 请求常量值引用是个坏主意 如果您正在访问指向的值,并且希望它不可为null,那么对底层类型的引用是好的 如果您希望它可以为空,可以使用
boost::optional
或T*
以及std::experimental
“世界上最笨的智能指针”(或同等的手写指针)。所有这些都是对某个变量的不可为空的引用
在界面中,不要要求你不需要的东西,也不要要求将来不需要的东西。这使得关于函数所做的事情的推理变得更加困难,并导致类似于OP中的问题。重置引用的函数与读取值的函数是完全不同的函数
现在,基于您的问题,一个更有趣的问题是,您希望函数重新放置智能指针,但您希望能够对共享和唯一的指针输入执行此操作。这是一种奇怪的情况,但我可以想象写一个类型擦除到emplace类型(一个
emplace\u sink
)
模板
使用later_ctor=std::函数;
模板
后期部署延迟部署(Args&…Args){
//依赖C++1z lambda引用绑定,手动编写
//如果这不能进入,或者不想依赖它:
返回[&](无效*ptr)->T*{
返回新的T(ptr)(std::forward(args));
};
}
命名空间详细信息{
模板
结构侵位目标{
虚拟~emplace_target(){}
虚拟T*emplace(以后的系数)=0;
};
}
模板
结构模板{
std::唯一的ptr pImpl;
模板
T*定位(Args&&…Args){
返回pImpl->emplace(延迟放置(std::forward(args)…);
}
模板
员工(标准::共享ptr和目标):
pImpl(新详细信息::emplace_shared_ptr(&target))//TODO
{}
模板
员工(标准::唯一性和目标):
pImpl(新详细信息::emplace_unique_ptr(&target))//TODO
{}
};
等等,需要大量的抛光。其思想是在任意上下文中键入对象T
的擦除构造。我们可能需要使用特例shared\u ptr
,这样我们就可以调用make\u shared
,因为void*->T*
延迟的ctor不足以实现这一点(不是根本上的,而是因为缺少API挂钩)
啊哈!我可以做一个没有特殊外壳的共享ptr
我们使用析构函数分配一块内存(
char[sizeof(T)]
),析构函数将缓冲区转换为T
,然后调用该缓冲区中的delete就地构造(获取T*
),然后通过共享ptr(共享ptr,T*)
构造函数转换为共享ptr
。小心例外,捕获这应该是安全的,我们可以使用定位函数将其定位到make_shared
组合缓冲区中。智能指针几乎不应该通过引用传递,除非您想谈论智能指针本身,而不是指针对象。使用.get()
或*
。为什么不呢?在旧的C++03中,传递指针是非常好的。现在,它只是成为拥有所有权的指针。我不明白为什么它会对你的决定产生影响。因为通常指针不是你感兴趣的对象,但指针对象是。如果你只是简单地修改传入的对象,你不需要麻烦使用智能指针——只需使用引用即可。如果参数可能是空的或无效的,请考虑使用诸如T*
的所有权不明确。因此,世界上最愚蠢的智能指针--std::experimental::observer_ptr
,它表示“我不拥有我指向的东西”,否则其行为就尽可能类似于T*
。T&
是不可为空的
void FancyAlgo(SomeType& value);
FancyAlgo(*ptr);
template<class T>
using later_ctor = std::function<T*(void*)>;
template<class T, class...Args>
later_ctor<T> delayed_emplace(Args&&...args) {
// relies on C++1z lambda reference reference binding, write manually
// if that doesn't get in, or don't want to rely on it:
return [&](void* ptr)->T* {
return new T(ptr)(std::forward<Args>(args));
};
}
namespace details {
template<class T>
struct emplace_target {
virtual ~emplace_target() {}
virtual T* emplace( later_ctor<T> ctor ) = 0;
};
}
template<class T>
struct emplacer {
std::unique_ptr<emplace_target<T>> pImpl;
template<class...Args>
T* emplace( Args&&... args ) {
return pImpl->emplace( delayed_emplace<T>(std::forward<Args>(args)...) );
}
template<class D>
emplacer( std::shared_ptr<T, D>& target ):
pImpl( new details::emplace_shared_ptr<T,D>(&target) ) // TODO
{}
template<class D>
emplacer( std::unique_ptr<T, D>& target ):
pImpl( new details::emplace_unique_ptr<T,D>(&target) ) // TODO
{}
};