一切都在问题中。我试过了:
#include <vector>
class Foo
{
int & _x;
public:
Foo(int x) :
_x(x)
{}
Foo(Foo && other) :
_x(other._x)
{}
Foo & operator=(Foo && other) = default;
private:
Foo(Foo const &) = delete;
Foo & operator=(Foo const &) = delete;
};
int main(void)
{
int a, b;
std::vector<Foo> vec;
vec.push_back(Foo(a));
vec.push_back(Foo(b));
vec.erase(vec.begin());
return 0;
}
但无法编译,因为默认情况下会删除Foo & operator=(Foo && other)
。
我试图删除此运算符,通过move强制编译器使用构造函数,但它尝试使用复制构造函数。
是否可以使用引用成员移动对象?
如果没有,为什么?
感谢。
编辑:我已经阅读了Move-assignment and reference member但它没有回答我的问题:我想知道编译器使用Foo & operator=(Foo const &)
的原因,而Foo(Foo && other)
可以使用。{/ p>
我无法理解为什么不能用引用成员移动一个类。
答案 0 :(得分:3)
您的问题是erase
要求元素类型为MoveAssignable
。这仅仅是因为erase
通常的实现方式:它在被擦除的元素(或元素)之后遍历向量,移动 - 分配给已擦除的插槽:
for (; j != end; ++i, ++j)
*i = std::move(*j);
for (; i != end; ++i)
i->~T();
这可以使用移动构造以不同的方式实现,但如果存在移动赋值运算符(大多数情况下)并且难以获得异常安全,那么这将是低效的:
for (; j != end; ++i, ++j)
{
i->~T();
new (&*i) T(std::move(*j)); // what if this throws?
}
for (; i != end; ++i)
i->~T();
您可以通过使用其他策略来解决此问题,以获得erase
的效果,例如:
vec = std::vector<Foo>(
std::make_move_iterator(std::next(vec.begin())),
std::make_move_iterator(vec.end()));
Foo
仍然不会非常有用,正是因为具有引用成员的类型不能移动 - 可赋值(Move-assignment and reference member);您应该考虑是否可以使用reference_wrapper
。