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