stschindler
stschindler

Reputation: 937

std::vector::erase() doesn't want to move

I've got a std::vector<Foo> where Foo is a class containing Foo( Foo&& ) noexcept.

Adding objects to the container works flawlessly, however erasing them using std::vector::erase( iterator ) does not, GCC 4.7 tries to call the assignment operator which I have deleted. The exact error message is:

error: use of deleted function ‘Foobar& Foobar::operator=(const Foobar&)

Edit: Of course std::vector calls the assignment operator, not the copy constructor (you can see that in the error message, too). Fixed it in the description, sorry.

Here's example source code as requested:

#include <vector>

class Foo {
    public:
        Foo() {}
        Foo( Foo&& other ) noexcept {}

        Foo( const Foo& ) = delete;
        Foo& operator=( const Foo& ) = delete;
};

int main() {
    std::vector<Foo> v;

    v.push_back( Foo{} );
    v.erase( v.begin() );
}

Upvotes: 10

Views: 2370

Answers (3)

Matthieu M.
Matthieu M.

Reputation: 299950

DeadMG's answer is excellent, however I'd like to promote another way of writing the assignment operator:

struct Foo {
    Foo() {}

    Foo(Foo const&) = delete;
    Foo(Foo&&) throw() { }

    Foo& operator=(Foo) throw() { return *this; }
};

Since you require a fresh temporary at the start of the method, the compiler will pick either the copy or move constructor to create this temporary on its own, and you do not have to write both a copy assignment operator AND a move assignment operator :)

Upvotes: 1

sehe
sehe

Reputation: 393174

I couldn't reproduce it. Turns out good habits go a long way: I had the move asignment operator defined.

Live on GCC 4.7.2: http://liveworkspace.org/code/36c600c285f2c91649fd4f73784c2c00

#include <iostream>
#include <vector>

struct Foo
{
    Foo() {}

    Foo(Foo const&) = delete;
    Foo(Foo&&) throw() { }

    Foo& operator=(Foo const&) = delete;
    Foo& operator=(Foo&&) throw() { return *this; }
};

int main(int argc, char* args[])
{
    std::vector<Foo> v;
    v.emplace_back();
    v.emplace_back();
    v.emplace_back();
    v.emplace_back();

    auto it = v.begin();
    it++;
    v.erase(it);
}

Upvotes: 2

Puppy
Puppy

Reputation: 146940

The problem is that you did not provide a move assignment operator. This is part of the vector Movable requirements for some functions.

Upvotes: 11

Related Questions