49

我编写了一个静态工厂方法,它返回一个从另一个数据对象填充的新 Foobar 对象。我最近一直沉迷于所有权语义,想知道我是否通过让这个工厂方法返回一个unique_ptr.

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

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

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

我的问题分为两部分:

  1. 这种方法是否传达了正确的所有权语义?
  2. 这是返回unique_ptr而不是原始指针的“坏习惯”吗?
4

3 回答 3

60

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

我认为这比返回一个原始指针要好得多(客户端必须记住如何以及是否处理该指针)。

但是,我不明白您关于释放指针以延长其寿命的评论。一般来说,我很少看到调用智能指针的任何理由release,因为我认为指针应该始终由某种 RAII 结构管理(我调用的唯一情况release是将指针放在不同的管理数据结构中,unique_ptr例如一个不同的删除器,在我做了一些需要额外清理的事情之后)。

因此,只要客户需要对象(或 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);

就我个人而言,我还将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);
于 2012-01-03T22:00:26.830 回答
17

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

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

于 2012-01-03T21:57:51.267 回答
6

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

于 2012-01-03T21:58:47.833 回答