为原始指针(如所有权语义)返回unique_ptr的不良做法



我编写了一个静态工厂方法,该方法返回从另一个数据对象填充的新Foobar对象。我最近痴迷于所有权语义,想知道我是否通过让这个工厂方法返回unique_ptr来传达正确的信息。

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

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

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);
//or:
std::shared_ptr<FooBar> myFoo = Foobar::factory(data);

就个人而言,我还会为返回的指针类型(在本例中为 std::unique_ptr<Foobar>(和/或使用的删除器(在本例中为 std::d efault_deleter(添加一个typedef到您的工厂对象。如果您稍后决定更改指针的分配,这会更容易(因此需要一种不同的方法来销毁指针,该方法将作为第二个模板参数 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);

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

这正是你想表达的:你说"这个函数的调用者:你现在是这个对象的唯一所有者;随心所欲地使用它,它的一生是你的责任。

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

最新更新