聪明智能指针:避免shared_ptr过度使用

时间:2016-05-20 10:41:13

标签: c++ c++11 smart-pointers

我遇到了像

这样的代码
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是一种“重型”;它有两个计数器和别名以及在大多数呼叫站点中真正看起来不需要的各种功能。然而,如果它是签名中的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 ++方式是返回指针而不是bool(并检查null)。在这种情况下,我不能为shared_ptr重载,但我可以将unique_ptr临时返回到shared_ptr变量,并且相应的构造函数将转换它。

但是,这样我就失去了make_shared的单一分配。我可以保存吗?

2 个答案:

答案 0 :(得分:12)

<!DOCTYPE html> <html> <head> <title>TODO supply a title</title> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> </head> <body> <input id="122" class='TabOnEnter' tabindex="1" /><br> <input id="123" class='TabOnEnter' tabindex="2" /><br> <input type="text" name="abc" /><br> <input type="text" name="abc1" /><br> <input type="text" name="abc2" /><br> <input type="text" name="abc3" class='TabOnEnter' tabindex="3" /><br> <input class='TabOnEnter' tabindex="4" /><br> <input class='TabOnEnter' tabindex="5" /><br> <input class='TabOnEnter' tabindex="6" /><br> <!-- <textarea class='TabOnEnter' tabindex="6">Hi, I am a test area</textarea>--> <input type="submit" value="submit" class='TabOnEnter' tabindex="7"> <script src="//code.jquery.com/jquery-2.1.1.min.js"></script> <script> $(document).on("keypress", ".TabOnEnter", function (e) { //Only do something when the user presses enter if (e.keyCode == 13) { var nextElement = $('[tabindex="' + (this.tabIndex + 1) + '"]'); console.log(this, nextElement); if (nextElement.length) nextElement.focus() else $('[tabindex="1"]').focus(); } }); //Hidden inputs should get their tabindex fixed, not in scope ;) //$(function(){ $('input[tabindex="4"]').fadeOut(); }) </script> </body> </html> 有一个converting constructor from std::unique_ptr。为什么不让函数按值返回std::shared_ptr

std::unique_ptr

这也可以作为一个工厂函数的文档,它将unique_ptr<resource> open_resource(...); 的所有权转移给调用者。

让来电者决定他们想要的方式:

resource

答案 1 :(得分:4)

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。