何时使用 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"?
据我所知,有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
表示我拥有一个对象。这只是说"我是一个物体"的另一种方式。因此,nullunique_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
,或者更好的是,抛出一个异常。
- 何时使函数成为类成员函数C++?
- 如何使一个函数具有三种不同的输出条件?
- 是否可以使一个类成为两个不同层次结构的子类?
- 如何使一个成员变量等于在main()中设置的另一个成员变量
- 如何使一个线程中的内存存储"promptly"在其他线程中可见?
- 使一个结构指向另一个结构
- 如何正确地使一个对象拥有另一个多态对象
- 如何使一个线程按预期顺序多次等待另一个线程
- 如何使一个函数的返回类型与另一个函数相同
- 对于具有两个模板化变量的模板化类,是否可以使一个 var 引用另一个 var
- 你应该在什么时候使一个类不可压缩
- 如何使一个方法在新线程中调用同一类中的另一个方法
- 如何使一个类的多个对象具有std::互斥
- SFML 2.1如何使一个精灵面对另一个精灵
- 如何在C++中使一个void函数与另一个void功能协同工作
- 如果您使一个char*ptr存储整数变量的地址,会发生什么
- 使一个类生成另一个类
- 使一个标头成为多个类包含所必需的
- 如何使一个shared_ptr的所有副本等于另一个shared_ptr
- 如何使一个类只能访问另一个类的某些私有成员