C++编译错误是由于使用 std::move 时运动构造函数与其他非运动构造函数之间的冲突

C++ compiling error due to a conflict between the movement constructor and other non-movement one when using std::move

本文关键字:运动 构造函数 其他 冲突 之间 move 错误 编译 于使用 C++ std      更新时间:2023-10-16

我正在对移动语义进行一些"实验",以便完全理解它。我已经到了我不完全理解的地步。这是因为在使用std::move时似乎与 A::A(B b)A::A(B &&b) 这样的构造函数存在冲突。下面是解释这一点的代码:

struct Item {
    Item() { }
    Item(const Item &other) {
        std::cout << "Item::Item(const Item& )n";
    }
};
struct Container {
    Container(Item i) {
        std::cout << "Container::Container(Item )n";
    }
    Container(Item &&i) {
        std::cout << "Container::Container(Item&& )n";
    }
};
int main() {
    Item i;
    Container c(std::move(i));
    return 0;
}

尝试编译上述代码时,显示以下错误:

error C2668: 'Container::Container' : ambiguous call to overloaded function
1>          c:usersxe74139documentsvisual studio 2012projectsproject1project1maincpp.cpp(21): could be 'Container::Container(Item &&)'
1>          c:usersxe74139documentsvisual studio 2012projectsproject1project1maincpp.cpp(17): or       'Container::Container(Item)'

我知道构造函数Container(Item i)根本没有意义,但我仍然不明白为什么编译器C++两个Container构造函数之间看到冲突。

为什么它不能确定Container c(i)用于呼叫Container(Item)Container c(std::move(i))用于呼叫Container(Item &&)

编辑:或者,换句话说,为什么构造函数Container(Item)对像Container c(std::move(i))这样的调用有效?

据我所知,这是因为参数首先被评估,然后通过。一旦它被传递,它就是任何r-value,你的两个构造函数都可以工作。我不确定是否有可能出现这样的过载,从我的角度来看这是没有意义的。

为什么不呢?好吧,您正在尝试定义一个强制元素移动的容器。从设计的角度来看,您必须考虑使用该代码的人可能不希望数据"被盗"(移动(。我认为在这种情况下,拥有以下内容会更有意义:

struct Item {
    Item() { }
    Item(const Item &other) {
        std::cout << "Item::Item(const Item& )n";
    }
    Item(Item &&other) {
        std::cout << "Item::Item(Item&&)n";
    }
};

这种重载更有意义 - 您将明确说明何时要移动对象以及何时复制对象(这里有一个默认move,但这种方式使其更加明显(。现在你只需要

Container(Item i);

(没有其他构造函数(并调用它

Container c(std::move(i));

是我们期望的 - 而不是复制i,你明确表示你想要移动它,i负责处理这个问题。

为什么构造函数 Container(Item( 对像 Container c(std::move(i(( 这样的调用有效?

因为当给定std::move(i)的结果(这是一个Item&&(时,您可以构造一个Item

就像 Howard Hinnant 在评论中所说的那样 - Item vs Item& 是一样的 - 你可以在传递另一个时构造一个,所以如果你定义了这两个构造函数,你就创建了友好。