9

如果我有一个find有时无法找到所需事物的函数,我倾向于使该函数返回一个指针,以便 anullptr指示未找到该事物。

例如

Student* SomeClass::findStudent(/** some criteria. */)

如果 Student 存在,它会返回一个指向找到的Student对象的指针,否则它会返回nullptr

我也看到boost::optional有人为此目的而提倡。例如,当您想要实现一个可以返回“无”的函数时,何时使用 boost::optional 以及何时使用 std::unique_ptr?

我的问题是,在这种情况下,返回指针不是最好的解决方案。ie 有可能找不到查询的项目,在这种情况下返回nullptr是一个完美的解决方案。使用类似的东西boost::optional(或任何其他类似的解决方案)有什么好处?

请注意,在我的示例中,findStudent只会返回指向 . 拥有的对象的指针SomeClass

4

4 回答 4

11

这里返回类型的优点optional<Student&>是使用的语义对于所有熟悉的用户来说都很明显optional(并且一旦他们熟悉它就会变得很明显)。这些语义是:

  • 调用者不拥有Student并且不负责内存管理。调用者只需获取对现有对象的引用。
  • 很明显,此功能可能会失败。你可能得到一个价值,你可能一无所获。很明显,调用者需要以一种或另一种方式检查结果。

optional<T>T*以一种不是的方式自我记录。此外,它还有其他好处,因为它可以在您想要返回任何类型的对象类型而无需分配的情况下工作。如果您需要返回intordoubleSomePOD怎么办?

于 2016-02-09T16:18:28.723 回答
6

optional<T&>被从 C++ 标准化轨道中删除,因为它的使用是有问题的:它的行为与非拥有几乎相同,但语义略有不同(并且与andT*令人困惑地不同)。optional<T>T*

optional<T&>基本上是一个非拥有T*的漂亮的包裹起来,而且有些奇怪。


现在,optional<T>是另一种野兽。

optional<Iterator>在基于容器的查找算法中使用过。我没有返回,而是end()返回空的可选项。这使用户无需比较即可确定他们是否未能找到该项目,并让代码如下:

if(linear_search_for( vec, item))

工作,而相同的算法还可以让您同时获得项目项目在容器中的位置(如果您确实需要它)。

指向元素的指针不会为您提供您可能想要的位置信息,除非使用连续容器。

所以在这里,我创建了一个可以为空的迭代器,它具有迭代器(通常与不同类型的容器一起工作)和指针(可以测试空状态)的优点。

下一个用途实际上是返回一个值。假设您有一个计算矩形的函数。

Rect GetRect();

现在,这很棒。但是如果这个问题没有意义呢?好吧,一种方法是返回一个空的矩形或其他“标志”值。

Optional 让您传达它可以返回一个矩形或什么都不返回,并且不使用空矩形来表示“无”状态。它使返回值可以为空。

int GetValue();

是一个更好的例子。无效值可以使用 int 的标志状态——比如说-1——但这会强制函数的每个用户查找和跟踪标志状态,而不是意外地将其视为正常状态。

相反,optional<int> GetValue()明确说明它可能会失败,以及失败的状态。如果它被填充,你知道它是一个真实的值,而不是一个标志值。

在这两种情况下,返回非拥有指针都是不可行的,因为谁拥有存储空间?返回一个拥有的指针是昂贵的,因为无意义的堆分配是没有意义的。

可选项是可为空的值类型。当你想在本地管理资源时,你仍然想要一个空的状态,他们会说清楚。


要研究的另一件事expected是提出的类型。这是一个可选的,但是当处于空状态时包含它为空的原因

于 2016-02-09T16:39:00.187 回答
3

optional<T&>可能确实被替换为T*T*没有明确的语义(所有权?)。

optional<T>不能代替T*。例如:

optional<Interval> ComputeOverlap(const Interval&, const Interval&);

如果没有重叠,则T*( nullptr) 或没有问题optional<T>。但是如果有重叠,我们需要创建一个新的区间。在这种情况下,我们可能会返回一个 smart_pointer,或者是可选的。

于 2016-02-09T16:34:34.537 回答
2

让我们假设您有一个std::map<IndexType, ValueType>您试图找到某些东西的地方(注意:这同样适用于其他容器,这只是一个示例)。您有以下选择:

  • 您返回一个ValueType&:用户可以修改您的地图内容,而无需考虑内存分配/释放。但是如果你在你的地图中没有找到任何东西,你需要抛出一个异常或类似的东西。
  • 您返回一个ValueType*:用户可以修改您的地图内容,如果您没有找到任何内容,您可以返回一个 nullptr。但是用户可以在该指针上调用 delete 并且您必须无论如何指定他是否必须这样做。
  • 您返回一个智能指针ValueType:用户不必担心删除或不删除,并且可以根据智能指针的类型修改您的地图内容。您也可以返回一个 nullptr。但这几乎需要您处理地图中的 smart_pointers,ValueType否则如果只是一个 int 则过于复杂。
  • 你返回一个简单ValueType的:用户不能修改你的地图内容,也不需要考虑内存分配/释放。但是如果你在你的地图中没有找到任何东西,你需要返回一些特殊ValueType的东西,告诉用户你没有找到任何东西。如果您ValueType是 eg int,您将返回哪个明确“未找到 int”。
  • ValueType您返回一个 boost::optional,这是您可以通过附加选项“不返回 a ValueType”获得的最接近简单的按值返回
于 2016-02-09T16:20:25.293 回答