是否可以创建一个只有const/reference成员的可移动类



一切都在问题中。我试过了:

#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

最新更新