聪明地使用智能指针:避免 shared_ptr 过度使用
Being smart with smart pointers: avoiding shared_ptr overuse
我遇到过类似
的代码
bool open_resource(..., shared_ptr<resource> & res)
{
...
shared_ptr<resource> newResource(new resource(...));
res = move(newResource);
return true;
}
然后用
调用
shared_ptr<resource> res;
open_resource(..., res);
然后,据我所知,res 没有以需要共享指针的方式使用。
当然立马想到换
shared_ptr<resource> newResource(new resource(...));
res = move(newResource);
和
res = make_shared<resource>(...)
...但后来我遇到了障碍。现在我不能再建议将 shared_ptr 引用更改为更基本的内容;至少如果我想确保,如果调用者以后确实需要 shared_ptr,则控制块有效地驻留在与对象相同的分配上。为此,它必须从一开始就是 shared_ptr。
另一方面,shared_ptr是"heavy"类型;它有两个计数器和别名以及在大多数呼叫站点中似乎真的不需要的各种功能。然而,如果签名中有 shared_ptr,他们就必须使用。
我看到的最佳解决方案是将函数体移动到辅助函数,然后重载。
bool get_resource_parameters(Param1& param1,..., ParamN& paramN)
{
...
}
bool open_resource(..., shared_ptr<resource> & res)
{
Param1 param1;
...
ParamN paramN;
if(!get_resource_parameters(param1,...,paramN))
return false;
res = make_shared<resource>(param1,...,paramN);
return true;
}
bool open_resource(..., unique_ptr<resource> & res)
{
Param1 param1;
...
ParamN paramN;
if(!get_resource_parameters(param1,...,paramN))
return false;
res = unique_ptr<resource>(new resource(param1,...,paramN));
return true;
}
但是真的不尽如人意
有没有人看到更好、更 C++ 的解决方案?
编辑
是的,C++ 方法是 return 指针而不是布尔值(并检查是否为空)。在这种情况下,我不能为 shared_ptr 重载,但我可以将 unique_ptr 临时 returned 分配给 shared_ptr 变量,适当的构造函数将转换它。
然而,这样我失去了make_shared的单一分配。我可以保存吗?
至allow unique_ptr
/shared_ptr
,您可以使用模板:
// Dispatcher for make_unique/make_shared
template <template <typename...> class Ptr, typename T>
struct make_helper;
template <typename T>
struct make_helper<std::unique_ptr, T>
{
template <typename ...Ts>
std::unique_ptr<T> operator() (Ts&&... args) const {
return std::make_unique<T>(std::forward<Ts>(args)...);
}
};
template <typename T>
struct make_helper<std::shared_ptr, T>
{
template <typename ...Ts>
std::shared_ptr<T> operator() (Ts&&... args) const {
return std::make_shared<T>(std::forward<Ts>(args)...);
}
};
template <template <typename...> class Ptr, typename T, typename ... Ts>
auto make(Ts&&... args)
{
return make_helper<Ptr, T>{}(std::forward<Ts>(args)...);
}
然后
bool get_resource_parameters(Param1& param1,..., ParamN& paramN)
{
//...
}
template <template <typename...> class Ptr>
Ptr<resource> open_resource(...)
{
Param1 param1;
...
ParamN paramN;
if(!get_resource_parameters(param1, ..., paramN))
return nullptr;
return = make<Ptr, resource>(param1, ..., paramN);
}
并检查 nullptr
而不是拆分 bool 和 smart_pointer。
std::shared_ptr
有一个 converting constructor from std::unique_ptr
。为什么不按值使函数 return 成为 std::unique_ptr
:
unique_ptr<resource> open_resource(...);
这也作为一个文档,表明这是一个将 resource
的所有权转移给调用者的工厂函数。
让来电者决定他们想要的方式:
auto x = open_resource(...);
// or
std::shared_ptr<resource> x{open_resource(...)};
我遇到过类似
的代码bool open_resource(..., shared_ptr<resource> & res)
{
...
shared_ptr<resource> newResource(new resource(...));
res = move(newResource);
return true;
}
然后用
调用shared_ptr<resource> res;
open_resource(..., res);
然后,据我所知,res 没有以需要共享指针的方式使用。
当然立马想到换
shared_ptr<resource> newResource(new resource(...));
res = move(newResource);
和
res = make_shared<resource>(...)
...但后来我遇到了障碍。现在我不能再建议将 shared_ptr 引用更改为更基本的内容;至少如果我想确保,如果调用者以后确实需要 shared_ptr,则控制块有效地驻留在与对象相同的分配上。为此,它必须从一开始就是 shared_ptr。
另一方面,shared_ptr是"heavy"类型;它有两个计数器和别名以及在大多数呼叫站点中似乎真的不需要的各种功能。然而,如果签名中有 shared_ptr,他们就必须使用。
我看到的最佳解决方案是将函数体移动到辅助函数,然后重载。
bool get_resource_parameters(Param1& param1,..., ParamN& paramN)
{
...
}
bool open_resource(..., shared_ptr<resource> & res)
{
Param1 param1;
...
ParamN paramN;
if(!get_resource_parameters(param1,...,paramN))
return false;
res = make_shared<resource>(param1,...,paramN);
return true;
}
bool open_resource(..., unique_ptr<resource> & res)
{
Param1 param1;
...
ParamN paramN;
if(!get_resource_parameters(param1,...,paramN))
return false;
res = unique_ptr<resource>(new resource(param1,...,paramN));
return true;
}
但是真的不尽如人意
有没有人看到更好、更 C++ 的解决方案?
编辑
是的,C++ 方法是 return 指针而不是布尔值(并检查是否为空)。在这种情况下,我不能为 shared_ptr 重载,但我可以将 unique_ptr 临时 returned 分配给 shared_ptr 变量,适当的构造函数将转换它。
然而,这样我失去了make_shared的单一分配。我可以保存吗?
至allow unique_ptr
/shared_ptr
,您可以使用模板:
// Dispatcher for make_unique/make_shared
template <template <typename...> class Ptr, typename T>
struct make_helper;
template <typename T>
struct make_helper<std::unique_ptr, T>
{
template <typename ...Ts>
std::unique_ptr<T> operator() (Ts&&... args) const {
return std::make_unique<T>(std::forward<Ts>(args)...);
}
};
template <typename T>
struct make_helper<std::shared_ptr, T>
{
template <typename ...Ts>
std::shared_ptr<T> operator() (Ts&&... args) const {
return std::make_shared<T>(std::forward<Ts>(args)...);
}
};
template <template <typename...> class Ptr, typename T, typename ... Ts>
auto make(Ts&&... args)
{
return make_helper<Ptr, T>{}(std::forward<Ts>(args)...);
}
然后
bool get_resource_parameters(Param1& param1,..., ParamN& paramN)
{
//...
}
template <template <typename...> class Ptr>
Ptr<resource> open_resource(...)
{
Param1 param1;
...
ParamN paramN;
if(!get_resource_parameters(param1, ..., paramN))
return nullptr;
return = make<Ptr, resource>(param1, ..., paramN);
}
并检查 nullptr
而不是拆分 bool 和 smart_pointer。
std::shared_ptr
有一个 converting constructor from std::unique_ptr
。为什么不按值使函数 return 成为 std::unique_ptr
:
unique_ptr<resource> open_resource(...);
这也作为一个文档,表明这是一个将 resource
的所有权转移给调用者的工厂函数。
让来电者决定他们想要的方式:
auto x = open_resource(...);
// or
std::shared_ptr<resource> x{open_resource(...)};