何时使用 boost::可选以及何时使用 std::unique_ptr 在你想要实现一个可以返回"nothing"的函数的情况下?

When to use boost::optional and when to use std::unique_ptr in cases when you want to implement a function that can return "nothing"?

本文关键字:何时使 一个 函数 nothing 情况下 返回 std boost unique ptr 实现      更新时间:2023-10-16

据我所知,有2*种方法可以实现一个函数,有时不返回结果(例如,在ppl列表中找到的人)。

*-忽略原始PTR版本,与bool标记配对,当没有找到版本时异常。

boost::optional<Person> findPersonInList();

std::unique_ptr<Person> findPersonInList();

那么有什么理由更喜欢一个而不是另一个吗?

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

如果你想返回一个句柄:

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

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

如果你想返回一个副本:

  • boost::optional<Person>为非多态类
  • std::unique_ptr<Person> for多态性类

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

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

boost::optional更清楚地表达了您的意图。您需要明确地说明,空std::unique_ptr意味着没有返回值

还有第四种方法:如果没有发现任何异常,则让函数抛出异常。

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

啊,Xeo还没出现?

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

  • unique_ptr表示我拥有一个对象。这只是说"我是一个物体"的另一种方式。因此,null unique_ptr会引起注意。我期待着一个目标,但我什么也没有得到;代码一定是错的!
  • optional意味着I有时可以不初始化,但这是ok的。在这种情况下,不用担心;如果它是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来表达这一点,以明确该函数可能不返回任何东西(不返回任何东西不是错误情况)。

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