std::vector::erase()不想移动

10

我有一个存储Foo类对象的std::vector<Foo>,其中Foo类包含Foo(Foo&&) noexcept构造函数。

向容器中添加对象工作得非常好,但是使用std::vector::erase(iterator)删除它们时则不行,GCC 4.7会尝试调用被我删除的赋值运算符。具体的错误信息如下:

error: use of deleted function ‘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() );
}

没有代码,很难看出问题所在。 - sehe
你的类名叫做 Foo,但是你收到了一个关于 Foobar 的错误信息?有些不匹配。请提供真实的代码。 - Pete Becker
3个回答

11

问题在于您没有提供移动赋值运算符。这是向量可移动要求的一部分,用于某些函数。


哦。呵呵。我刚刚打了自己的示例,并自动添加了移动赋值运算符。这就解释了为什么它对我有效 :) +1 - sehe
1
编译器错误提示了一切 - 没有合适的 operator= 运算符。 - Puppy

2

我无法重现它。原来良好的习惯有益处:我已经定义了移动赋值运算符。

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

其实这是一个非常好的想法,但是 erase() 不支持移动迭代器,它会报错:没有匹配的函数调用 std::move_iterator<...> - stschindler
1
我刚刚注意到并更新了代码。原来在“发明”复制样本时,我自动定义了移动赋值运算符,正如@DeadMG所建议的那样。习惯... - sehe
呵呵,有趣。非常感谢,提供移动赋值运算符也是完全合理的。 - stschindler
使用throw()noexcept有什么特别的原因,还是它们是同义词? - ildjarn
@ildjarn 我本地的gcc版本还没有接受这个关键字。我猜它们大致意思相同,但是throw()有很多问题,所以我更喜欢使用noexcept - sehe

1

DeadMG的回答非常好,但我想推荐另一种编写赋值运算符的方式:

struct Foo {
    Foo() {}

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

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

由于您需要在方法开始时使用新的临时对象,编译器将自行选择复制构造函数或移动构造函数来创建此临时对象,因此您不必编写复制赋值运算符和移动赋值运算符两者 :)


他无论如何都不行,因为他的类是不可复制的。 - Puppy
@DeadMG:我会避免详细介绍什么是自动默认和什么是自动删除的...这太古怪了。 - Matthieu M.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接