【问题标题】:Returning unique_ptr<Object> as unique_ptr<const Object>返回 unique_ptr<Object> 作为 unique_ptr<const Object>
【发布时间】:2018-05-05 07:21:41
【问题描述】:

我有这样的方法:

std::unique_ptr<const Stats> Table::GetStats() const {
  std::unique_ptr<Stats> result;
  // ...
  // Prepare stats. Under some conditions an exception may be thrown.
  // ...
  return result;
}

问题是它无法编译:

错误:无法将‘std::unique_ptr’左值绑定到‘std::unique_ptr&&’

我可以通过使用以下绕过来编译它:

return std::unique_ptr<const Stats>(result.release());

但这似乎有点过分了。我无法理解,从 C++ 的角度来看,第一段代码有什么问题?有没有更优雅的解决方案?

【问题讨论】:

  • 编译器版本?为我工作。 godbolt.org/g/DZak6n
  • @RichardHodges, gcc (Debian 4.9.2-10+deb8u1) 4.9.2
  • @RichardHodges 可能你会在没有 OP 的情况下获得 RVO // Prepare stats. Under some conditions an exception may be thrown.
  • @Alexey 那是旧的。这将是越野车。你可以试试return { std::move(result) };
  • @RichardHodges 原始海报,帖子所有者

标签: c++ c++11 return constants unique-ptr


【解决方案1】:

您的代码应该可以正常工作,因为在return statement:

(强调我的)

(C++11 起)

如果表达式是左值表达式和复制的条件 省略被满足或将被满足,除非表达式命名为 函数参数,然后重载决议选择构造函数 用于返回值的初始化执行两次: 首先好像表达式是一个右值表达式(因此它可以选择 引用 const 的移动构造函数或复制构造函数), 如果没有合适的转换可用,则重载分辨率为 第二次执行,使用左值表达式(因此它可以选择 复制构造函数引用非常量)。

即使函数返回类型不同,上述规则也适用 从表达式的类型(复制省略需要相同的类型)

也就是说,即使result是左值,一开始也会被认为是右值,然后会选择下面的constructor,它可以将std::unique_ptr&lt;Stats&gt;转换为std::unique_ptr&lt;const Stats&gt;

template< class U, class E >
unique_ptr( unique_ptr<U, E>&& u ) noexcept;

gcc4.9.2 的行为似乎不是这种方式(即首先将表达式视为右值表达式); gcc 9 工作正常。

作为@RichardHodges commented,您可以使用std::move 作为workaround

【讨论】:

  • 编译器不需要(在 C++17 之前)执行任何复制省略,因此它的行为正确。 std::move 确实是要走的路。
  • @Pezo 它只是要求“满足复制省略的条件......”,而不是实际应用复制省略。
  • 标准中有复制省略的条件吗?是否已定义但不是必需的?
  • @Pezo 我不确定我是否完全理解您的问题。有关允许编译器执行复制省略的条件,请参阅en.cppreference.com/w/cpp/language/copy_elision。正如你所说,从 C++17 开始,它是强制性的。
  • 我明白了,有条件允许这样做,因为它可以改变可观察的行为。我总是以好像的方式思考它,那么它总是被允许的。
猜你喜欢
  • 1970-01-01
  • 2013-01-30
  • 2019-12-28
  • 2016-06-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多