隐式移动构造函数和赋值运算符 [英] Implicit move constructor and assignment operator

查看:81
本文介绍了隐式移动构造函数和赋值运算符的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

什么是隐式移动构造函数执行成员级移动,而隐式移动分配运算符执行成员级分配?

What does it mean that implicit move constructor does a member-wise move and implicit move assignment operator a member-wise assignment?

来自 https://en.cppreference.com/w/cpp/language/move_constructor :

对于非联盟类类型(类和结构), move构造函数执行对象基础的完整成员移动,并且是非静态的成员,按照其初始化顺序,使用直接初始化带有xvalue参数.如果满足constexpr构造函数,生成的move构造函数为constexpr.

For non-union class types (class and struct), the move constructor performs full member-wise move of the object's bases and non-static members, in their initialization order, using direct initialization with an xvalue argument. If this satisfies the requirements of a constexpr constructor, the generated move constructor is constexpr.

来自 https://en.cppreference.com/w/cpp/language/move_assignment :

对于非联盟类类型(类和结构),移动分配操作员对对象的对象执行完整的成员级移动分配直接基地和直接非静态成员在其声明中顺序,对标量使用内置分配,按成员数组的移动分配,类的移动分配运算符类型(称为非虚拟类型).

For non-union class types (class and struct), the move assignment operator performs full member-wise move assignment of the object's direct bases and immediate non-static members, in their declaration order, using built-in assignment for the scalars, memberwise move-assignment for arrays, and move assignment operator for class types (called non-virtually).

对于下面的示例类模板,隐式成员看起来像这样:

Will the implicit members look like this for the following exemplary class template:

template<class T>
class Holder {
public:
    Holder(int size) : m_size(size) { m_data = new T[m_size]; }

    Holder(Holder && other) :
        m_size(std::move(other.m_size)),
        m_data(std::move(other.m_data))
    {}

    Holder& operator=(Holder && other) {
       if(this == &other) return *this;
       m_data = std::move(other.m_data);
       m_size = std::move(other.m_size);
       return *this;
    }

    ~Holder() { delete [] m_data; }
private:
    T* m_data;
    int m_size;
};

此外,上例中的 std :: move()将传输哪些资源?

What's more, what will the std::move() in the above example transfer the resources?

推荐答案

如果进一步查看链接页面,您将看到类编译器生成的move构造函数(和move赋值运算符)实际上是 Trivial :

If you look further down you linked page, you will see that your classes compiler generated move constructor (and move assignment operator) will actually be Trivial:

小举动作构造器

如果满足以下所有条件,则类T的move构造函数很简单:

  • 它不是用户提供的(意味着它是隐式定义的或默认的);
  • T没有虚拟成员函数;
  • T没有虚拟基类
  • 为T的每个直接基数选择的move构造函数很简单;
  • 为T的每个非静态类类型(或类类型数组)成员选择的move构造函数很简单;

平凡的移动构造函数是执行动作的构造函数,它与平凡的复制构造函数相同,即,复制简单的构造函数.对象表示,就像通过std :: memmove 一样.所有数据类型与C语言兼容(POD类型)是微不足道的.

A trivial move constructor is a constructor that performs the same action as the trivial copy constructor, that is, makes a copy of the object representation as if by std::memmove. All data types compatible with the C language (POD types) are trivially movable.

(强调我的)

这两个成员变量是POD类型,因此可以轻松移动.由于您的类不是虚拟的,并且不包含任何非平凡的成员,因此它是微不足道的,并且将复制所有数据成员.如评论中所述,这将导致您的指针和UB双重删除.

The two member variables are POD types and therefore are trivially movable. Since your class is not virtual and it holds no non-trivial members it is therefore trivial and all the data members will be copied. As mentioned in the comments, this will lead to double deleting your pointer and UB.

既然是这种情况,您需要通过获取已移动对象指针的所有权并将其设置为 nullptr 来正确实现您的移动语义.或者更好的是,只需使用 std :: vector 甚至是 std :: unique_ptr .

Since this is the case, you need to implement your move semantics properly, by taking ownership of the moved objects pointer and setting it to nullptr. Or better yet, just use std::vector or even std::unique_ptr.

这篇关于隐式移动构造函数和赋值运算符的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆