23

据我了解,有两种方法可以实现有时不返回结果的函数(例如在 ppl 列表中找到的人)。

*- 我们忽略原始 ptr 版本,与 bool 标志配对,并在未找到版本时出现异常。

boost::optional<Person> findPersonInList();

或者

std::unique_ptr<Person> findPersonInList();

那么有什么理由比另一个更喜欢一个吗?

4

7 回答 7

26

这取决于:您希望返回句柄还是副本

如果你想返回一个句柄

  • Person*
  • boost::optional<Person&>

都是可以接受的选择。我倾向于使用一个Ptr<Person>在空访问的情况下抛出的类,但这是我的偏执狂。

如果您想退回副本

  • boost::optional<Person>对于非多态类
  • std::unique_ptr<Person>对于多态类

因为动态分配会产生开销,所以您只在必要时使用它。

于 2013-01-16T14:46:13.127 回答
14

一般的答案是你的意图是由boost::optional而不是由表达的std::unique_ptr。也就是说,您的find操作的特殊情况可能应该符合标准库的执行方式,假设您的基础类型具有迭代器的概念:end()如果没有找到元素,则返回迭代器,否则返回元素的迭代器。

于 2013-01-16T14:43:24.763 回答
8

boost::optional更清楚地说明你的意图。您需要明确记录空std::unique_ptr意味着没有返回值

于 2013-01-16T14:40:40.823 回答
6

还有第四种方法:如果没有找到任何东西,让函数抛出异常。

我知道这并不能真正回答你的问题,因此我很抱歉,但也许你没有考虑过。

于 2013-01-16T14:39:51.713 回答
5

啊,Xeo还没出现?

好吧,我告诉过你一次,我再告诉你一次:这两个是完全不同的对象,具有不同的目的。

  • unique_ptr表示我拥有一个对象。这只是说“我是一个对象”的不同方式。因此,nullunique_ptr是可以引起注意的东西。我期待一个对象,但我什么也没得到;代码一定是错的!
  • optional意味着我有时不能被初始化,但没关系。在这种情况下,不用担心;如果是None,那就是已经想到的行为。

两者都隐式转换为 bool 的事实并不意味着它们可以互换使用。optional与可能不会产生任何输出的代码一起使用(例如,读取流)。unique_ptr在工厂对象中使用;他们很可能会为您创建一个对象,如果没有,则抛出异常。

关于您的示例的结论:find应该返回optional

于 2013-01-16T14:46:11.850 回答
3

考虑到可为空的要求,从概念上归结为:

std::optional具有值语义,堆栈存储。

std::unique_ptr有移动语义,堆存储。

如果您想要值语义和堆存储,请使用std::indirect http://open-std.org/JTC1/SC22/WG21/docs/papers/2016/p0201r1.pdf

(如果你想要移动语义和堆栈存储......我不知道。我猜它是一个带有堆栈分配器的 unique_ptr?)

于 2017-05-11T22:38:25.087 回答
1

那么有什么理由比另一个更喜欢一个吗?

他们表达了非常不同的意图:optional说函数可能不会给出结果给你(这不是错误情况)。unique_ptr告诉您有关所有权语义的一些信息(并且更容易与 null 一起使用以表示错误)。

通常我会使用最能表达界面背后意图的那个。

例如,假设您正在编写一个 HTTP 服务器,它试图将接收到的缓冲区解析为一个 HTTP 请求对象。当您尝试解析不完整的缓冲区时,不会出现错误情况,您只需等待并缓冲更多数据,然后再试一次。

我将使用optional, 来表达这一点,以明确该函数可能不返回任何内容(并且不返回任何内容不是错误情况)。

如果我的解析必须验证东西(例如,如果解析的表达式是无效的正则表达式,则正则表达式解析器应该产生错误)我会返回一个 null unique_ptr,或者更好的是,抛出一个异常。

于 2013-01-16T15:02:13.360 回答