运算符 + 需要移动构造函数

operator + need Move Constructors

本文关键字:移动 构造函数 运算符      更新时间:2023-10-16

我无法编译附加的项目,因为我删除了移动构造函数。

这是预期的行为吗?如果编译器不使用移动构造函数,为什么还需要它?

Windows-Visual Studio 2015 14.0.25431.01 更新3

#include <string>
#include <sstream>
#include <vector>
class poo {
public:
poo() = default;
poo(poo&&) = delete; //deleted function
virtual ~poo() = default;
poo operator +(const poo &a) const {
poo to_return;
to_return._s += a._s;
return to_return;
//moveconstructors.cpp(14): error C2280: 'poo::poo(poo &&)': attempting to reference a deleted function
}
private:
std::string _s;
};
int main(int, char **) {
poo a;
return 0;
}

编辑 1: 添加"便便(常量便便&)=默认值;"后会发生相同的结果;

编辑2: Windows-Visual Studio 2019 16.1.0 Preview 2.0 也会发生相同的结果

。编辑3: 添加/修改后发生相同的结果

poo(const std::string &s) : _s(s) {
}
poo operator +(const poo& a) const {
return poo(_s + a._s);
}

编辑4:它适用于vs2019和/std:c ++ 17

poo(poo&&) = delete;

是的,此行禁用移动构造函数,但它也会删除复制构造函数。

来自class.copy.ctor:

如果类定义未显式声明复制构造函数,则隐声明非显式构造函数。 如果类定义声明了移动构造函数或移动赋值运算符,则隐式声明的副本 构造函数定义为已删除;。

现在,如果标准保证命名返回值优化 (NRVO),那么这一切都没什么大不了的,因为编译器可以看到您的operator+具有单个局部变量的返回。在这种情况下,我们不需要复制或移动构造函数;poo实例将被创建并通过引用("在引擎盖下")传递给 FN。

请注意,在 C++17 中,您可以使用保证复制 (RVO) 来解决此问题:

poo(std::string s) : _s(std::move(s)){}
poo operator +(const poo &a) const {
return poo(_s + a._s);
}

演示

但是,即使在 C++20 中,命名返回值优化也尚未得到保证。允许实现改用移动操作。

[class.copy.elision] 指出:

在以下复制初始化上下文中,可以使用移动操作代替复制操作:
- 如果return语句中的表达式是一个(可能是括号)id-表达式,该表达式命名一个对象,并在最内层封闭函数或lambda 表达式

此处允许省略优化 (NRVO),但对象在语义上仍必须是可复制/可移动的;通过删除移动构造函数,您还删除了复制构造函数,因此这两个操作都无效,程序格式不正确。

您可以重新添加复制 ctor:

poo(const poo&) = default;

(而且,即使您使用的是 C++17,其保证省略也不适用于左值。