Подтвердить что ты не робот

std :: vector :: erase() не хочет двигаться

У меня есть std::vector<Foo> где Foo - класс, содержащий Foo( Foo&& ) noexcept.

Добавление объектов в контейнер работает безупречно, однако удаление их с помощью std::vector::erase( iterator ) не происходит, GCC 4.7 пытается вызвать оператор присваивания, который я удалил. Точное сообщение об ошибке:

ошибка: использование удаленной функции Foobar & Foobar :: operator = (const Foobar &)

Редактирование: Конечно, std::vector вызывает оператор присваивания, а не конструктор копирования (вы также можете увидеть это в сообщении об ошибке). Исправлено это в описании, извините.

Вот пример исходного кода в соответствии с запросом:

#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() );
}
4b9b3361

Ответ 1

Проблема в том, что вы не предоставили оператор присваивания переадресации. Это часть вектора Подвижные требования для некоторых функций.

Ответ 2

Я не мог воспроизвести его. Оказывается, хорошие привычки проходят долгий путь: у меня был заданный оператор перемещения.

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);
}

Ответ 3

Ответ DeadMG превосходный, однако я хотел бы продвигать другой способ написания оператора присваивания:

struct Foo {
    Foo() {}

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

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

Поскольку для начала этого метода требуется новое временное значение, компилятор выбирает конструктор копирования или перемещения для создания этого временного объекта самостоятельно, и вам не нужно писать оператор присваивания копий И оператор назначения перемещения :)