工厂的C ++生命周期返回智能指针

时间:2015-11-07 14:13:22

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

我在C ++ 11中使用工厂模式,它在我的 main()函数的范围内,并且被调用如下:

histogram_requests -> AddNewPostfix( Postfix_factory :: get_postfix( "Layers", ntuple_reader ) );

Postfix_factory :: get_postfix()是一个静态成员函数,返回 std :: unique_ptr<后缀> 即可。示例返回值为:

return std :: move( std :: unique_ptr<Postfix>( new Layers_postfix( ntuple_reader_p ) ));

我的第一个问题是,这实际上是否有效?返回的指针是否在 main()范围的末尾被销毁?

第二件事是我想把这个指针传递给一个函数。这样做的正确方法是什么?当我将 AddNewPostFix()的参数类型设置为 std :: unique_ptr std :: unique_ptr&amp;&amp; 时,我的程序会编译但作为一个简单的参考失败。我不想让我的 AddNewPostFix()意外删除指针中的数据,但我不确定其中任何一个都是安全的。谁能告诉我如何正确安全地做到这一点?

2 个答案:

答案 0 :(得分:1)

return std :: move( std :: unique_ptr<Postfix>( new Layers_postfix( ntuple_reader_p ) ));

这里有两点值得注意:

  1. You don't need std::move in your return statement.

  2. 您应该使用std::make_unique。它仅在C ++ 14之后得到官方支持,但无论如何您的编译器都支持它,或者您可以轻松创建自己的版本。

  3.   

    返回的指针是否在main()范围的末尾被销毁?

    “返回的指针”可以引用几件事。

    当然,std::unique_ptr对象已被销毁。当范围结束时,所有本地对象都将被销毁。 std::unique_ptr内部的原始指针数据成员也被销毁,但这很简单。

    我认为你真正的意思是指向的对象,由std::unique_ptr管理,即动态分配的Postfix。该对象也将被销毁,是的,因为当std::unique_ptr结束时,main不会移动到任何位置。

    如果Postfix不会被破坏,那么你就会有内存泄漏而std::unique_ptr几乎没用,不是吗?

      

    第二件事是我想把这个指针传递给一个函数。这样做的正确方法是什么?

    这个问题太宽泛了。 Herb Sutter曾写过an entire article about passing smart pointers to functions。这是一篇很长的文章,也有很多有趣的用户评论。你一定要读它。以下是Sutter的指南:

      

    除非您愿意,否则不要将智能指针作为函数参数传递   使用或操纵智能指针本身,例如共享或   转让所有权。

      

    首选按值,*或&amp;而不是智能指针传递对象。

      

    使用按值unique_ptr参数表达“接收器”功能。

      

    仅使用非const unique_ptr&参数修改unique_ptr

      

    不要使用const unique_ptr&作为参数;使用widget*代替

      

    表示函数将使用按值shared_ptr参数存储和共享堆对象的所有权。

      

    仅使用非const shared_ptr&参数来修改shared_ptr。仅当您不确定是否要复制并分享所有权时,才使用const shared_ptr&作为参数;否则使用widget*代替(或者如果不可为空,则使用widget&)。

      

    我不想让我的AddNewPostFix()意外删除指针中的数据,但我不确定其中任何一个都是安全的。

    最安全的做法是不要传递指针而是Postfix&Postfix const&。当然,人们仍然可以尝试delete &postfix或采用类似的不良做法。但俗话说,C ++可以防范墨菲,而不是对抗马基雅维利。

    这是一个完整的例子:

    #include <memory>
    #include <string>
    #include <iostream>
    
    struct Postfix
    {
        std::string layers;
        int ntuple_reader;
    
        Postfix(std::string const& layers, int ntuple_reader) :
            layers(layers),
            ntuple_reader(ntuple_reader)
        {
        }
    
        ~Postfix()
        {
            std::cout << "dtr\n";
        }
    };
    
    std::unique_ptr<Postfix> get_postfix(std::string const& layers, int ntuple_reader)
    {
        return std::make_unique<Postfix>(layers, ntuple_reader);
    }
    
    void AddNewPostfix(Postfix const& postfix)
    {
        std::cout << "AddNewPostfix\n";
        // do something with postfix.layers and postfix.ntuple_reader
    }
    
    int main()
    {
        int ntuple_reader = 123;
        auto postfix_ptr = get_postfix("Layers", ntuple_reader);
        AddNewPostfix(*postfix_ptr);
    }
    

    正如您在输出中看到的那样,Postfix的末尾正确调用了main的析构函数。

答案 1 :(得分:-1)

返回智能指针是正常的,直到您决定需要将其保存在不同类型的智能指针中。我只是返回一个原始指针,让调用者决定它想用它做什么。在你的情况下,std :: move是不必要的。

要将它传递给函数,请将函数参数设为const T&amp;并在智能指针上使用解除引用运算符。

void someFunction(const T& t)
{
}

std::unique_ptr<T> t = ...;
SomeFunction(*t);