2012-01-03 72 views
47

我写过一个静态工厂方法,它返回从另一个数据对象填充的新Foobar对象。我最近一直痴迷于所有权语义,并且想知道如果我通过让这个工厂方法返回unique_ptr来传达正确的信息。返回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代替原始指针?
+0

您正在返回一个unqiue_ptr告诉客户端他们拥有指针?这与我所期望的完全相反(因为他们必须明确地获得唯一指针的所有权)。 – jknupp 2012-01-03 21:54:53

+1

您可能想使用移动语义(如果您能够使用C++ 11)。有了这个,用户可以决定如何延长工厂创建的对象的生命周期。 – evnu 2012-01-03 21:57:35

+1

@evnu这是你自动完成的事情,不是吗? – 2012-01-03 22:20:09

回答

58

从一个工厂方法返回一个std::unique_ptr是蛮好的,应该是一个值得推荐的做法。它传递的信息是(IMO):您现在是此物件的唯一拥有者。此外,为了您的方便,对象知道如何摧毁自己。

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

但是我不明白你的关于释放指针延长它的生命周期评价。总的来说,我很少看到任何理由骂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); 

个人而言,我也为返回的指针类型添加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); 
+3

我不是故意提到'release()'是误导性的或令人困惑的,对不起。这个新代码正在进入一个相当大的现有应用程序(一百二十万行C++),它不使用任何智能指针(COM除外)。我知道我的团队中的其他人会担心,如果遗留代码使其有效“需要”,那么如果没有合理的方法可以达到原始指针。当然,我会给出适当的警告,并建议在可能的情况下坚持使用unique_ptr/shared_ptr。我真的很喜欢你的typedef想法,它将你的答案与James McNellis'区别开来。感谢您的见解。 – 2012-01-04 13:26:44

17

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

这就是你想什么来表达:你说“这个函数的调用者:你现在是此对象的唯一拥有者,用它做什么,请你,它的寿命是你的责任。”

+0

的确,但为什么不让它返回一个'std :: shared_pointer <>'?它达到了相同的效果,但允许指针的多个副本。 – 2012-01-03 21:59:36

+8

@AndréCaron:如果您只想将所有权转让给调用者,为什么强制使用'std :: shared_ptr'?如果调用者想要将对象的所有权赋予“std :: shared_ptr”(或者如果调用者想要的话,则为其他类型的智能指针)。 – 2012-01-03 22:01:04

+7

@AndréCaron:原因基本上是表现。工厂无法知道客户端是否会将'std :: shared_ptr'添加的功能放在'std :: unique_ptr'上,所以为什么会牺牲一些功能的性能,这可能不是必需的。由于'shared_ptr'可以构造并从'unique_ptr'分配,所以确实没有好处。 – Grizzly 2012-01-03 22:11:12

6

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

相关问题