一切都在问题中。我试过了:
#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;
}
但由于默认删除了CCD_ 1,因此无法编译。
我试图删除这个运算符,通过移动强制编译器使用构造函数,但它试图使用复制构造函数。
是否可以使用引用成员移动对象?
如果没有,为什么?
谢谢。
编辑:我已经阅读了Move赋值和引用成员,但它并不能回答我的问题:我想知道为什么编译器使用Foo & operator=(Foo const &)
,而Foo(Foo && other)
可以工作。
我无法理解为什么不能移动具有引用成员的类。
您的问题是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
仍然不是很有用,正是因为具有引用成员的类型不能移动可赋值(移动赋值和引用成员);您应该考虑是否可以使用reference_wrapper
。