为什么返回右值时不调用移动构造函数?

德尼·斯特列尔佐夫

我创建了一个类Animal

class Animal {
public:
    Animal() = default;
    Animal(Animal&& a) = delete;
    Animal(Animal& a) = delete;

    Animal& operator=(Animal&& a) = delete;
    Animal& operator=(Animal& a) = delete;
};

Animal func1() {
    return Animal();
}

Animal func2() {
    Animal a {};
    return a;
}

int main(void) {
    Animal a1 = func1();
    Animal a2 = func2();
    return 0;
}

我不明白为什么func1()可以正常工作:return Animal()创建一个右值对象并a1在函数中使用该对象进行初始化main如我所见,它等于

Animal a1 = func1()
         ==
Animal a1 = Animal&& temp   //(I wrote type in assignment for clarifying)

我已经读过返回值是一个右值;但是,在func2我得到一个错误,“复制构造函数被删除”而不是移动构造函数,为什么?

阿努普·拉纳

情况1

在这里,我们考虑以下声明:

 Animal a1 = func1();

调用表达式func1()是一个rv类型的值Animal从 C++17 开始,由于强制复制 elison

在以下情况下,编译器必须省略类对象的复制和移动构造,即使复制/移动构造函数和析构函数具有可观察到的副作用。对象直接构建到存储中,否则它们将被复制/移动到。复制/移动构造函数不需要存在或可访问

  • 在 return 语句中,当操作数是与函数返回类型相同的类类型(忽略 cv 限定)的纯右值时:

也就是说,对象直接构建到存储中,否则它们将被复制/移动到。也就是说,在这种情况下(对于 C++17),不需要可用的复制/移动构造函数。所以这个声明有效。

案例2

在这里,我们考虑以下声明:

Animal a2 = func2();

这里来自非强制性复制 elison

在以下情况下,编译器允许但不需要省略类对象的复制和移动(C++11 起)构造,即使复制/移动(C++11 起)构造函数和析构函数具有可观察的一面-效果。对象直接构建到存储中,否则它们将被复制/移动到。这是一种优化:即使它发生并且没有调用复制/移动(自 C++11 起)构造函数,它仍然必须存在且可访问(就好像根本没有发生任何优化一样),否则程序会出错 -形成:

  • 在 return 语句中,当操作数是具有自动存储持续时间的非易失性对象的名称时,它不是函数参数或 catch 子句参数,并且属于相同的类类型(忽略 cv 限定)函数返回类型。

也就是说,复制/移动构造函数必须存在(即这些 ctor 必须存在且可访问),但由于您已明确将它们标记为已删除,因此此语句失败并出现错误

error: use of deleted function ‘Animal::Animal(Animal&&)’

错误也可以在这里看到

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

为什么在函数返回时不调用复制构造函数?

为什么在这种情况下调用非常量右值移动构造函数?

为什么operator *不调用构造函数?

为什么不调用move构造函数

为什么原始的卷曲构造函数{}不返回右值?

为什么右值引用类型的赋值不调用移动赋值运算符?

为什么函数不调用左值

当对象构造函数抛出新表达式时,为什么不调用释放函数?

当抛出前一个异常时从(创建/复制/移动)构造函数中抛出异常时,为什么不调用 std::terminate()?

为什么此函数不调用move构造函数?

为什么要在移动构造函数中移动右值引用?

当对象作为参数传递时,为什么不调用我的自定义构造函数?

当有右值构造函数可用时,为什么从右值调用类引用构造函数重载?

为什么要调用移动构造函数?

为什么不调用模板化副本构造函数?

为什么不调用基类2的构造函数?

为什么不调用实现Runnable接口的类的构造函数?

当将对象作为参数传递时,为什么要调用析构函数但不调用构造函数?

为什么调用复制构造函数而不是移动构造函数?

为什么调用复制构造函数而不是移动构造函数?

为什么我们在编写装饰器时不调用函数而不是返回它?

返回时,为什么调用复制构造函数而不是move构造函数?

为什么在函数返回后不调用desctructor?

尽管传递了右值,为什么我的move构造函数没有被调用?

为什么仅在虚拟渲染时不调用函数

为什么 React 按钮在点击时不调用函数

为什么在lambda中移动时未调用move构造函数?

为什么在移动Unique_ptr时在lambda中调用复制构造函数?

为什么在赋值时调用移动构造函数?