为什么在C ++ 11或C ++ 14中,当我声明移动赋值运算符时,编译器会隐式删除副本构造函数?

问题描述

我想创建一个包含迭代器类的列表数据结构。一切正常,但是当我声明移动赋值运算符时,如果程序使用的是C ++ 14或C ++ 11标准,则不会编译,但是在C ++ 17,C ++ 2a中可以正常工作。

list.h:

#pragma once

#include <iostream>

template <typename T>
class list {
    struct node {
        node(T data,node* prev = nullptr,node* next = nullptr)
            : data{ data },prev{ prev },next{ next } {}
        
        T data;
        node* prev;
        node* next;
    };
public:
    struct iterator {
        template <typename>
        friend class list;

        explicit iterator(node *_node = nullptr) 
            : _node(_node) {}

        iterator& operator=(iterator const &it) {
            _node = it._node;
        
            return *this;
        }
       
        iterator& operator=(iterator &&it) {
            // does nothing
            return *this;
        }

        T& operator*() {
            return _node->data;
        }

    private:
        node *_node;
    };

    list(T data) {
        Head = Tail = new node(data);

        size = 1;
    }

    iterator begin() {
        return iterator(Head);
    }
private:
    node* Head;
    node* Tail;

    int size;
};

main.cpp:

#include "list.h"

int main() {

    list<int> lst(100);

    std::cout << *lst.begin() << std::endl;

}

这是一个简化的版本,但足以描述问题。

编译器错误和注释消息:

error: use of deleted function ‘constexpr list::iterator::iterator(const list::iterator&)’
     return iterator(Head);
                         ^

note: ‘constexpr list::iterator::iterator(const list::iterator&)’ is implicitly declared as
       deleted because ‘list::iterator’ declares a move constructor or move assignment operator
     struct iterator {
        ^~~~~~~~

解决方法

return iterator(Head);

这在C ++ 17中起作用的原因是在C ++ 17中是guaranteed copy elision。这里没有复制或移动。

在return语句中,当操作数是同一类的prvalue时 类型(忽略cv-qualification)作为函数返回类型:

在C ++ 17之前,这需要一个构造函数,但是已定义的移动赋值运算符将其删除,在C ++ 17中也将其删除,但是复制省略不需要它(同上):

复制/移动构造函数不需要存在或不可访问