糟糕的做法返回unique_ptr原始指针像所有权语义? [英] Bad practice to return unique_ptr for raw pointer like ownership semantics?

查看:163
本文介绍了糟糕的做法返回unique_ptr原始指针像所有权语义?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我写了一个静态工厂方法,返回一个新的Foobar对象从另一个数据对象填充。我最近一直痴迷于所有权语义,我想知道如果我传达正确的消息,让这个工厂方法返回 unique_ptr

  class Foobar {
public:
static unique_ptr< Foobar>工厂(DataObject数据);
}



我的目的是告诉客户代码他们拥有指针。没有智能指针,我只需返回 Foobar * 。然而,我想强制要求删除此内存以避免潜在的错误,因此 unique_ptr 似乎是一个合适的解决方案。如果客户端想要延长指针的生命周期,他们只需调用 .release(),一旦他们得到 unique_ptr

  Foobar * myFoo = Foobar :: factory(data).release 

我的问题分为两部分:


  1. 这种方法是否传达正确的所有权语义?

  2. 这是一个不好的做法,返回 unique_ptr

    返回 std:>

    :unique_ptr 从工厂方法是很好,应该是一个推荐的做法。它传达的消息是(IMO): 您现在是此对象的唯一所有者。此外,为了方便,对象知道如何销毁自己。 $ /

    我认为这比返回一个原始指针客户必须记住如何和如果处理这个指针)。



    但是我不明白你对释放指针的意见,以延长它的生命周期。一般来说,我很少看到任何理由在smartpointer上调用 release ,因为我认为指针应该总是由某种RAII结构管理(只有我调用 release 是将指针放在不同的管理数据结构中,例如:一个 unique_ptr 以保证额外的清理)。



    因此,客户端可以(而且应该)将 unique_ptr > unique_ptr ,它已经从返回的构造移动),只要他们需要对象(或 shared_ptr ,如果他们需要多个副本的指针)。所以客户端代码应该看起来更像这样:

      std :: unique_ptr< FooBar> myFoo = Foobar :: factory(data); 
    //或:
    std :: shared_ptr< FooBar> myFoo = Foobar :: factory(data);

    我也会添加 typedef 返回的指针类型(在这种情况下 std :: unique_ptr< Foobar> )和或者使用的deleter(在这种情况下,std :: default_deleter)这使得更容易,如果你后来决定更改指针的分配(因此需要一个不同的方法来销毁指针,这将作为第二个模板参数可见 std :: unique_ptr )。
    所以我会这样做:

      class Foobar {
    public:
    typedef std :: default_deleter< Foobar>去除剂
    typedef std :: unique_ptr< Foobar,deleter> unique_ptr;

    static unique_ptr factory(DataObject data);
    }

    Foobar :: unique_ptr myFoo = Foobar :: factory(data);
    //或:
    std :: shared_ptr< Foobar> myFoo = Foobar :: factory(data);


    I've written a static factory method that returns a new Foobar object populated from another data object. I've recently been obsessed with ownership semantics and am wondering if I'm conveying the right message by having this factory method return a unique_ptr.

    class Foobar {
    public:
        static unique_ptr<Foobar> factory(DataObject data);
    }
    

    My intent is to tell client code that they own the pointer. Without a smart pointer, I would simply return Foobar*. I would like, however, to enforce that this memory be deleted to avoid potential bugs, so unique_ptr seemed like an appropriate solution. If the client wants to extend the lifetime of the pointer, they just call .release() once they get the unique_ptr.

    Foobar* myFoo = Foobar::factory(data).release();
    

    My question comes in two parts:

    1. Does this approach convey the correct ownership semantics?
    2. Is this a "bad practice" to return unique_ptr instead of a raw pointer?

    解决方案

    Returning a std::unique_ptr from a factory method is just fine and should be a recommended practice. The message it conveys is (IMO): You are now the sole owner of this object. Furthermore, for your convenience, the object knows how to destroy itself.

    I think this is much better then returning a raw pointer (where the client has to remember how and if to dispose of this pointer).

    However I do not understand your comment about releasing the pointer to extend it's lifetime. In general I rarely see any reason to call release on a smartpointer, since I think pointers should always be managed by some sort of RAII structure (just about the only situation where I call release is to put the pointer in a different managing datastructure, e.g. a unique_ptr with a different deleter, after I did something to warrant additional cleanup) .

    Therefore the client can (and should) simply store the unique_ptr somewhere (such as another unique_ptr, which has been move constructed from the returned one) as long as they need the object (or a shared_ptr, if they need multiple copies of the pointer). So the clientside code should look more like this:

    std::unique_ptr<FooBar> myFoo = Foobar::factory(data);
    //or:
    std::shared_ptr<FooBar> myFoo = Foobar::factory(data);
    

    Personally I would also add a typedef for the returned pointer type (in this case std::unique_ptr<Foobar>) and or the used deleter (in this case std::default_deleter) to your factory object. That makes it easier if you later decide to change the allocation of your pointer(and therefore need a different method for destruction of the pointer, which will be visible as a second template parameter of std::unique_ptr). So I would do something like this:

    class Foobar {
    public:  
        typedef std::default_deleter<Foobar>     deleter;
        typedef std::unique_ptr<Foobar, deleter> unique_ptr;
    
        static unique_ptr factory(DataObject data);
    }
    
    Foobar::unique_ptr myFoo = Foobar::factory(data);
    //or:
    std::shared_ptr<Foobar> myFoo = Foobar::factory(data);
    

    这篇关于糟糕的做法返回unique_ptr原始指针像所有权语义?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆