首页 > 解决方案 > 为什么我需要移动`std::unique_ptr`

问题描述

给定以下代码:

#include <iostream>
#include <memory>

struct A {};

struct B : public A {};

std::pair<bool, std::unique_ptr<B>> GetBoolAndB() {
    return { true, std::make_unique<B>() };
}

std::unique_ptr<A> GetA1() {
    auto[a, b] = GetBoolAndB();
    return b;
}

std::unique_ptr<A> GetA2() {
    auto [a, b] = GetBoolAndB();
    return std::move(b);
}

GetA1无法编译,出现以下错误:

C2440: 'return': cannot convert from 'std::unique_ptr<B,std::default_delete<_Ty>>' to 'std::unique_ptr<A,std::default_delete<_Ty>>'

whileGetA2编译没有错误。

我不明白为什么我需要调用std::move才能使函数工作。

编辑

只是为了澄清,正如 DanielLangr 在评论中指出的那样,我的怀疑是关于

std::unique_ptr<A> GetA3() {
    std::unique_ptr<B> b2; 
    return b2;
}

无需std::move.

现在我明白在 and 的情况下GetA1GetA2对于结构化绑定,它恰好b是某个对象的一部分,因此必须将其移动以成为右值引用。

标签: c++c++17unique-ptrmove-semanticsstructured-bindings

解决方案


我不明白为什么我需要调用 std::move 来使函数工作。

因为对应的构造函数std::unique_ptr有一个右值引用类型的参数:

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

有关详细信息,请参阅文档:https ://en.cppreference.com/w/cpp/memory/unique_ptr/unique_ptr

由于右值引用不能绑定左值,因此,您不能使用b(左值)作为此构造函数的参数。

如果您想知道为什么b在语句中被视为左值return,请参阅例如:为什么结构化绑定禁用 RVO 并继续返回语句?简而言之,b不是具有自动存储持续时间的变量,而是对pair元素的引用。

错误消息基本上只是说编译器找不到任何可行的转换构造函数,因此,它“无法转换......”。

b通过使用call包装std::move,您正在创建一个引用与 相同的对象的表达式b,但它的类别是右值。这可能与该构造函数参数绑定。


推荐阅读