据我了解,有两种方法可以实现有时不返回结果的函数(例如在 ppl 列表中找到的人)。
*- 我们忽略原始 ptr 版本,与 bool 标志配对,并在未找到版本时出现异常。
boost::optional<Person> findPersonInList();
或者
std::unique_ptr<Person> findPersonInList();
那么有什么理由比另一个更喜欢一个吗?
据我了解,有两种方法可以实现有时不返回结果的函数(例如在 ppl 列表中找到的人)。
*- 我们忽略原始 ptr 版本,与 bool 标志配对,并在未找到版本时出现异常。
boost::optional<Person> findPersonInList();
或者
std::unique_ptr<Person> findPersonInList();
那么有什么理由比另一个更喜欢一个吗?
这取决于:您希望返回句柄还是副本。
如果你想返回一个句柄:
Person*
boost::optional<Person&>
都是可以接受的选择。我倾向于使用一个Ptr<Person>
在空访问的情况下抛出的类,但这是我的偏执狂。
如果您想退回副本:
boost::optional<Person>
对于非多态类std::unique_ptr<Person>
对于多态类因为动态分配会产生开销,所以您只在必要时使用它。
一般的答案是你的意图是由boost::optional
而不是由表达的std::unique_ptr
。也就是说,您的find
操作的特殊情况可能应该符合标准库的执行方式,假设您的基础类型具有迭代器的概念:end()
如果没有找到元素,则返回迭代器,否则返回元素的迭代器。
boost::optional
更清楚地说明你的意图。您需要明确记录空std::unique_ptr
意味着没有返回值
还有第四种方法:如果没有找到任何东西,让函数抛出异常。
我知道这并不能真正回答你的问题,因此我很抱歉,但也许你没有考虑过。
啊,Xeo还没出现?
好吧,我告诉过你一次,我再告诉你一次:这两个是完全不同的对象,具有不同的目的。
unique_ptr
表示我拥有一个对象。这只是说“我是一个对象”的不同方式。因此,nullunique_ptr
是可以引起注意的东西。我期待一个对象,但我什么也没得到;代码一定是错的!optional
意味着我有时不能被初始化,但没关系。在这种情况下,不用担心;如果是None
,那就是已经想到的行为。两者都隐式转换为 bool 的事实并不意味着它们可以互换使用。optional
与可能不会产生任何输出的代码一起使用(例如,读取流)。unique_ptr
在工厂对象中使用;他们很可能会为您创建一个对象,如果没有,则抛出异常。
关于您的示例的结论:find
应该返回optional
。
考虑到可为空的要求,从概念上归结为:
std::optional
具有值语义,堆栈存储。
std::unique_ptr
有移动语义,堆存储。
如果您想要值语义和堆存储,请使用std::indirect
http://open-std.org/JTC1/SC22/WG21/docs/papers/2016/p0201r1.pdf。
(如果你想要移动语义和堆栈存储......我不知道。我猜它是一个带有堆栈分配器的 unique_ptr?)
那么有什么理由比另一个更喜欢一个吗?
他们表达了非常不同的意图:optional
说函数可能不会给出结果给你(这不是错误情况)。unique_ptr
告诉您有关所有权语义的一些信息(并且更容易与 null 一起使用以表示错误)。
通常我会使用最能表达界面背后意图的那个。
例如,假设您正在编写一个 HTTP 服务器,它试图将接收到的缓冲区解析为一个 HTTP 请求对象。当您尝试解析不完整的缓冲区时,不会出现错误情况,您只需等待并缓冲更多数据,然后再试一次。
我将使用optional
, 来表达这一点,以明确该函数可能不返回任何内容(并且不返回任何内容不是错误情况)。
如果我的解析必须验证东西(例如,如果解析的表达式是无效的正则表达式,则正则表达式解析器应该产生错误)我会返回一个 null unique_ptr
,或者更好的是,抛出一个异常。