如何有效地返回 std::Optional

Jiř*_*ner 13 c++ optimization c++17 stdoptional

我想问如何以std::optional有效的方式返回 an 并且我想使用std::make_optional(). 例如,让我们有这个代码片段:

std::optional<Path> CreateCanonicalPath(const std::string_view& path)
{
  std::error_code errorCode;
  const auto result = std::filesystem::weakly_canonical(std::filesystem::u8path(path), errorCode);
  return !errorCode ? std::make_optional(result) : std::nullopt;
}
Run Code Online (Sandbox Code Playgroud)

result我特别感兴趣的是传递给是否有任何优化std::make_optional。使用起来会不会比较好std::make_optional(std::move(result))

它是否可以防止任何 RVO 或 NVRO?这result是一个局部变量,但它并不完全在 return 语句中,所以我假设编译器不能单独使用 move 。

Sam*_*hik 15

有一个明显的改进:

std::optional<Path> CreateCanonicalPath(const std::string_view& path)
{
  std::error_code errorCode;
  auto result = std::filesystem::weakly_canonical(std::filesystem::u8path(path), errorCode);
  return !errorCode ? std::make_optional(std::move(result)) : std::nullopt;
}
Run Code Online (Sandbox Code Playgroud)

制作临时对象const将需要使用复制构造作为实例化返回的一部分std::optional。这种调整应该导致采用移动语义。

此后,任何进一步的改进都将高度依赖于编译器的行为。这不太可能,但如果进行基准测试,则可以使用替代语法观察到一些较小的性能差异,例如:

std::optional<Path> CreateCanonicalPath(const std::string_view& path)
{
  std::error_code errorCode;
  auto result = std::make_optional(std::filesystem::weakly_canonical(std::filesystem::u8path(path), errorCode));

  if (errorCode)
     result.reset();

  return result;
}
Run Code Online (Sandbox Code Playgroud)

如果确定编译器将选择删除副本(正如 NVRO 所允许的那样),那么也值得对此进行基准测试。但只有实际的基准测试才会产生有用的结果。