代码之家  ›  专栏  ›  技术社区  ›  Alexey

将unique\u ptr<Object>返回为unique\u ptr<const Object>

  •  5
  • Alexey  · 技术社区  · 6 年前

    我有这样一种方法:

    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\u ptr–levalue绑定到–std::unique\u ptr&&–掼

    我可以使用以下旁路进行编译:

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

    但这似乎有点过分。我不明白,从C++的角度来看,第一段代码有什么问题?还有更优雅的解决方案吗?

    1 回复  |  直到 6 年前
        1
  •  4
  •   songyuanyao    6 年前

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

    (重点矿山)

    (自C++11以来)

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

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

    也就是说,即使 result 是左值,首先将其视为右值,然后 constructor 将被选中,它可以转换 std::unique_ptr<Stats> std::unique_ptr<const Stats>

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

    似乎是gcc4。9.2不这样做(即首先将表达式视为右值表达式); gcc 9 一切正常。

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