DiveIntoML
DiveIntoML

Reputation: 2537

C++ insert class without copy assignment into deque

I'm inserting a class that has copy constructor but does not have copy assignment into a deque, and a simple example is shown below:

class X {
public:
    X(const int value): value(value) {}
    const int value;
};

void insert() {
    std::deque<X> queue;
    X x(3);
    queue.insert(queue.begin(), x); // this cannot compile
    queue.emplace(queue.begin(), x); // this cannot compile
    queue.emplace_front(x); // this is OK
}

The compiler complains that the class X does not have a copy assignment due to the const int value in the definition. I understand the part that it does not have a copy assignment, but it indeed has a copy constructor, and I thought to insert into a deque, the element will be copy-constructed, hence I only need a copy constructor and not a copy assignment, where am I wrong here? And how do I deal with this kind of situation where I only have copy constructor and not copy assignment due to const fields?

Upvotes: 0

Views: 75

Answers (1)

Fran&#231;ois Andrieux
Fran&#231;ois Andrieux

Reputation: 29022

"I thought to insert into a deque, the element will be copy-constructed, hence I only need a copy constructor and not a copy assignment". The requirements depend on which function you use :

For std::deque<T>::emplace :

Type requirements

-T (the container's element type) must meet the requirements of MoveAssignable, MoveInsertable and EmplaceConstructible.

emplace won't work with X because it can't be move assigned.

For std::deque<T>::emplace_front :

Type requirements

-T (the container's element type) must meet the requirements of EmplaceConstructible.

emplace_front is what you were thinking of and does work with X since it is emplace constructible.

The reason the two functions have different requirements is that elements in a deque are stable under front and back insertion. When you insert an element at the front or back of the deque all pointers and references to its existing elements remain valid, nothing has to move.

With emplace that guarantee isn't provided because it can insert elements anywhere in the container. If you insert in the middle of the container, some number of elements might need to be shifted, so elements need to be assignable to allow this shift. Passing begin() as the iterator doesn't help, the function is implemented to accommodate the case where the iterator may not be begin() or end().

Upvotes: 2

Related Questions