C++ 为原始指针(如所有权语义)返回 unique_ptr 的错误做法?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/8719119/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 19:02:18  来源:igfitidea点击:

Bad practice to return unique_ptr for raw pointer like ownership semantics?

c++smart-pointersunique-ptrownership-semantics

提问by Bret Kuhns

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.

我编写了一个静态工厂方法,它返回一个从另一个数据对象填充的新 Foobar 对象。我最近一直痴迷于所有权语义,并且想知道我是否通过让这个工厂方法返回一个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_ptrseemed 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*. 但是,我想强制删除此内存以避免潜在的错误,因此unique_ptr似乎是一个合适的解决方案。如果客户端想要延长指针的生命周期,他们只需.release()在获得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_ptrinstead of a raw pointer?
  1. 这种方法是否传达了正确的所有权语义?
  2. 这是返回unique_ptr而不是原始指针的“不良做法”吗?

回答by Grizzly

Returning a std::unique_ptrfrom 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.

std::unique_ptr从工厂方法返回 a很好,应该是推荐的做法。它传达的信息是 (IMO):您现在是该对象的唯一所有者。此外,为方便起见,对象知道如何销毁自己。

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 releaseon a smartpointer, since I think pointers should always be managed by some sort of RAII structure (just about the only situation where I call releaseis to put the pointer in a different managing datastructure, e.g. a unique_ptrwith a different deleter, after I did something to warrant additional cleanup) .

但是,我不明白您关于释放指针以延长其生命周期的评论。总的来说,我很少看到任何理由骂release上一个智能指针,因为我觉得指针应该总是通过某种RAII结构(只是这里我所说的只是情况的管理release是把指针在不同的管理数据结构,例如unique_ptr用一个不同的删除器,在我做了一些事情以保证额外的清理之后)。

Therefore the client can (and should) simply store the unique_ptrsomewhere (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:

因此,只要客户端需要对象(或者 a ,如果他们需要多个指针副本),客户端就可以(并且应该)简单地存储unique_ptr某个地方(例如 another unique_ptr,它是从返回的一个移动构造shared_ptr的)。所以客户端代码应该更像这样:

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

Personally I would also add a typedeffor 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:

就个人而言,我还会typedef为返回的指针类型(在本例中std::unique_ptr<Foobar>)和/或使用的删除器(在本例中为 std::default_deleter)添加到您的工厂对象。如果您以后决定更改指针的分配(因此需要不同的方法来销毁指针,该方法将作为 的第二个模板参数可见),这会更容易std::unique_ptr。所以我会做这样的事情:

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);

回答by James McNellis

A std::unique_ptruniquely owns the object to which it points. It says "I own this object, and no one else does."

Astd::unique_ptr唯一拥有它指向的对象。它说“我拥有这个对象,没有其他人拥有。”

That is exactly what you are trying to express: you are saying "caller of this function: you are now the sole owner of this object; do with it as you please, its lifetime is your responsibility."

这正是您要表达的意思:您是在说“此函数的调用者:您现在是此对象的唯一所有者;随心所欲地使用它,它的生命周期是您的责任。”

回答by Dietmar Kühl

It exactly conveys the correct semantics and is the way I think all factories in C++ should work: std::unique_ptr<T>doesn't impose any kind of ownership semantics and it is extremely cheap.

它准确传达了正确的语义,并且是我认为 C++ 中的所有工厂都应该工作的方式:std::unique_ptr<T>不强加任何类型的所有权语义,而且非常便宜。