I wanted to create a list data structure with an iterator class in it. Everything works well but when I declare a move assignment operator the program doesn't compile if it's using the C++14 or C++11 standards, but works fine in 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;
}
It's a stripped-down version but it's enough to describe the problem.
Compiler error and note message:
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 {
^~~~~~~~
When to delete copy constructor and assignment operator? Copy constructor (and assignment) should be defined when ever the implicitly generated one violates any class invariant. It should be defined as deleted when it cannot be written in a way that wouldn't have undesirable or surprising behaviour.
The copy constructor and copy-assignment operator are public but deleted. It is a compile-time error to define or call a deleted function. The intent is clear to anyone who understands =default and =delete . You don't have to understand the rules for automatic generation of special member functions.
Explanation: The copy constructor can be defined as private. If we make it private then the objects of the class can't be copied. It can be used when a class used dynamic memory allocation. Explanation: The object should not be modified in the copy constructor.
In the C++ programming language, the move assignment operator = is used for transferring a temporary object to an existing object. The move assignment operator, like most C++ operators, can be overloaded. Like the copy assignment operator it is a special member function.
return iterator(Head);
Why this works in C++17 is because in C++17 this is guaranteed copy elision. No copy or move takes place here.
In a return statement, when the operand is a prvalue of the same class type (ignoring cv-qualification) as the function return type:
Prior to C++17, this requires a constructor, but the defined move assignment operator deletes it, it's also deleted in C++17, but copy elision does not require it (ibid):
The copy/move constructors need not be present or accessible
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With