当右值不实现move时,在具有move语义的容器上实现insert()
Implementing insert() on a container with move semantics when rvalue does not implement move
我正在尝试实现一个容器,该容器提供具有复制和移动语义的插入方法。
实现是这样的:
template <typename T> class Buffer {
// lots of stuff ommitted here
...
// copy semantics
Buffer<T>::Iterator push(const T& item) {
Buffer::Iterator head = push();
*head = item;
return head;
}
// move semantics
Buffer<T>::Iterator push(T&& item) {
Buffer::Iterator head = push();
*head = std::move(item);
return head;
}
}
如果类型T(要被推入缓冲区的类型)实现了移动赋值运算符,那么这就可以很好地工作。然而,如果我试图推送类似以下内容的实例,我会遇到编译器错误:
struct Foo {
Foo(int a) : m_bar(a) {}
int m_bar;
Foo& operator=(Foo& other) {
this.m_bar = other.m_bar;
}
}
如果我试图编译buffer.push(Foo(42));
,我会在读取*head = std::move(item);
的行上得到push(T&& item)
-方法的编译器错误。错误是operator=
没有接受右值的可行重载——这是正确的,没有。只有一个赋值运算符接受lvalues。
但是,由于我不能确保存储在容器中的每个对象都有一个正确实现的移动分配运算符,我需要确保正确处理这种情况。更重要的是,std::vector可以毫无问题地处理这个问题。当一个对象实现移动赋值时,push_back
会移动它,如果不是,它会复制它。不管它是否是右值。事实上,如果我把之前导致错误的有问题的Foo
右值放入std::向量中,它的工作原理应该是这样的。
那么我错过了什么?我的容器如何实现移动语义,并且仍然支持未实现移动赋值的对象的右值引用?
您正在做/假设错误的是复制分配运算符的错误签名:
Foo& operator=(Foo& other);
其采用对CCD_ 7实例的非常量左值引用。如果没有用户提供的赋值运算符获取右值引用(也就是说,右值可以由常量左值引用绑定),这可以防止移动返回到常规副本,因此它应该是:
Foo& operator=(const Foo& other);
// ~~~~^
那么为什么它能与
std::vector<Foo>
一起工作呢
buffer.push_back(Foo(42));
语句使用复制构造函数,而不是赋值运算符。这是有效的,因为Foo
有一个隐式生成的复制构造函数,用于以下签名:
Foo(const Foo&);
它同时适用于左值和右值(DEMO)。
你想做的事:
*head = std::move(item);
是使用赋值运算符。由于您已经自己声明了一个,编译器不能隐式生成采用常量左值引用的,也不能使用用户声明的采用非常量左值参考的,这会导致您看到的错误。
考虑在push
操作中使用分配器或placement-new运算符,使用item
参数作为Foo
构造函数的参数,而不是使用复制赋值和移动赋值运算符。
- 如果没有malloc,链表实现将失败
- 如何在c++中实现处理器调度模拟器
- 如何在c++中使用引用实现类似python的行为
- 实现无开销push_back的最佳方法是什么
- 使用简单类型列表实现的指数编译时间.为什么
- 我应该实现右值推送功能吗?我应该使用std::move吗
- 实现move构造函数如何影响返回值优化
- 无法理解 std::move 的实现
- 使用 std::move 实现"take"方法。
- 当右值不实现move时,在具有move语义的容器上实现insert()
- 在C中实现C++标准11的std::move函数
- 如何实现菱形继承的move构造函数
- 通过调用Move赋值操作符实现Move构造函数
- 使用const_cast实现move构造函数
- 双链表实现中的"Conditional jump or move depends on uninitialised value"
- 在二维数组上实现move赋值运算符
- 通过move赋值实现B=f(A)语法
- 根据move构造函数实现复制赋值操作符
- 当基类提供move语义时,派生类是否需要实现它
- 在遵循pimpl设计模式的类中实现move语义的正确方法是什么?