我们经常不得不在软件中表示一个可能缺失的值。不同的编程语言为此目的进行了抽象。
最新版本的 C++ (C++17) 引入了 std::optional 模板。这有点整洁。您可以编写打印字符串的代码,或者在没有可用字符串时发出警告,如下所示:
void f ( std :: optional < std :: string > s ) { 标准:: cout < < s 。 value_or ( “无字符串” ) << std :: endl ; }
我希望 std::optional 在处理普通对象(整数、std::string_view 等)时相对有效。然而,如果你想避免复制你的对象,你应该小心使用 std::optional。
让我们考虑这个例子:
A f ( std ::可选的< A > z ) { 返回z 。 value_or ( A ( ) ) ; } A g ( ) { A a ( "消息" ) ; auto z = std :: optional < A > ( a ) ; 返回f ( a ) ; }
调用函数g()时构造了多少个字符串类的实例?最多五个实例:
- 在函数的开头我们构造了一个 A 的实例。
- 然后我们在将它传递给 std::optional<A> 时复制构造这个实例。
- 将 std::optional<A> 传递给函数 f 涉及另一个副本。
- 在 value_or 构造中,我们有一个 A 的默认构造(在这种情况下这是浪费工作)。
- 最后,当对 value_or 的调用终止时,我们复制构造一个 A 的实例。
优化编译器有可能消除或所有多余的构造,特别是如果您可以内联函数,以便编译器可以看到无用的工作并修剪它。但是,一般来说,您可能会遇到效率低下的代码。
我不建议反对使用 std::optional。有一些有效的策略可以避免复制。如果性能是一个问题,请多加注意。
原文: https://lemire.me/blog/2023/01/12/care-is-needed-to-use-c-stdoptional-with-non-trivial-objects/