假设我有一个容器,为了参数,让我们说一个向量:
std::vector<T> v;
并假设我的类型'T'有一个移动ctor:
T(T&& move_from) noexcept //...implementation
但是我没有移动赋值运算符。
是否可以将值移动到类型T到向量内某个索引的位置?类似于我可以将元素插入两个元素之间或最后通过使用以下方式移动它的方式:
v.emplace(std::move(value));
v.emplace_back(std::move(value));
......每个人似乎建议更换矢量元素的方法是使用:
v.at(index) = value;
然而,必须调用复制ctor(或者操作符=复制是规范地调用)。
我想到了在所需索引处的元素上使用std::swap
以及我希望移入的值,但是,由于我不需要我的值,所以它似乎有点浪费如果我没有在我的类上定义swap()
,那么std :: swap似乎只是调用两个元素的副本ctor ...这只会使整个事情的成本增加两倍。
如何在向量和stl容器中的索引处移动元素(如果可以推广)?有没有理由说这首先不应该是可行的?
注意,我问这对于只定义了标准移动ctor的类型是如何实现的,如果我在类型上定义swap(),我可以看到它变得相当容易。然而,交换方法的存在似乎并不常见,所以我宁愿避免这种情况......更不用说当方法不可用时,我不得不用sfinae来解决这个问题(这将导致代码不可读)或遭受双重调用复制的惩罚。
答案 0 :(得分:4)
v.at(index) = std::move(value)
取决于是否存在移动赋值运算符。 std::swap
解决方案需要一个nothrow移动赋值运算符。
同样,定义T::swap
肯定没有什么不好,它可能比回到std::swap
更有效。
为T
编写移动赋值运算符将是一个很好的解决方案。如果你不能做到这一点,那么它就可以在原地制造和销毁,例如:
T *ptr = &v.at(index);
ptr->~T();
new(ptr) T( std::move(value) );
依赖于T
的移动构造函数为noexcept,否则如果它抛出则会被填充。
使用swap
或移动分配的一个很好的理由是它本质上是异常安全的。移动赋值运算符也有利于其他容器操作。