当我可以返回指针时,为什么要使用boost :: optional

时间:2016-02-09 15:59:59

标签: c++ c++11 boost-optional

如果我有find函数有时无法找到所需的东西,我倾向于使该函数返回一个指针,使nullptr表示找不到该东西。

E.g。

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

如果学生存在,它将返回指向找到的Student对象的指针,否则它将返回nullptr

我也看到boost::optional也提倡这个目的。例如。 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"?

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

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

4 个答案:

答案 0 :(得分:10)

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

  • 调用方不拥有Student,也不负责内存管理。调用者只需获取对现有对象的引用。
  • 很明显,此功能可能会失败。您可能获得一个值,而您可能什么也得不到。很明显,呼叫者需要以某种方式检查结果。

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

答案 1 :(得分:5)

optional<T&>已从C ++标准化轨道中删除,因为它的使用值得怀疑:它的行为几乎与非拥有T*的行为略有不同(并且与optional<T>和{混淆不同} {1}})语义。

T*基本上是非拥有的optional<T&>,非常奇怪。

现在,T*是一个不同的野兽。

我在基于容器的查找算法中使用了optional<T>。我没有返回optional<Iterator>,而是返回空的可选项。这样,用户无需比较即可确定是否找不到项目,并允许代码如下:

end()

工作,而同样的算法还允许您在项目中获取容器中项目的位置(如果您确实需要它)。

除了连续的容器外,指向元素的指针不会提供您可能需要的位置信息。

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

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

if(linear_search_for( vec, item))

现在,这很棒。但如果这个问题毫无意义呢?好吧,一种方法是返回一个空的rect或其他“flag”值。

可选让你通知它可以返回一个矩形,或者什么都不是,而不是使用空矩形来表示“无”状态。它使返回值可以为空。

Rect GetRect();

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

相反,-1表明它可能会失败,失败的状态。如果已填充,则表示它是实际值,而不是标记值。

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

Optionals是可以为空的值类型。如果您想在本地管理资源,并且仍然想要一个空状态,那么它们就会明确。

要研究的另一件事是提出的optional<int> GetValue()类型。这是可选的,但当处于空状态时包含原因为什么它是空的。

答案 2 :(得分:3)

optional<T&>可能确实被T*取代,但T*没有明确的语义(所有权?)。

optional<T>无法取代T*。 例如:

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

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

答案 3 :(得分:2)

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

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