为什么在 C++11 或 C++14 中,当我声明移动赋值运算符时,编译器会隐式删除复制构造函数?
Why in C++11 or C++14 does the compiler implicitly delete the copy constructor when I declare a move assignment operator?
我想创建一个包含迭代器 class 的列表数据结构。一切正常,但是当我声明一个移动赋值运算符时,如果程序使用 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。此处不进行复制或移动。
In a return statement, when the operand is a prvalue of the same class
type (ignoring cv-qualification) as the function return type:
在C++17之前,这需要一个构造函数,但是定义的移动赋值运算符删除了它,它在C++17中也被删除了,但是复制省略不需要它(同上):
The copy/move constructors need not be present or accessible
我想创建一个包含迭代器 class 的列表数据结构。一切正常,但是当我声明一个移动赋值运算符时,如果程序使用 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。此处不进行复制或移动。
In a return statement, when the operand is a prvalue of the same class type (ignoring cv-qualification) as the function return type:
在C++17之前,这需要一个构造函数,但是定义的移动赋值运算符删除了它,它在C++17中也被删除了,但是复制省略不需要它(同上):
The copy/move constructors need not be present or accessible