【问题标题】:C++ moving into a containerC++ 移入容器
【发布时间】:2018-01-06 08:39:25
【问题描述】:

假设我有一个容器,为了论证,我们假设一个向量:

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 解决这个问题(这将使代码不可读)或遭受对复制 ctor 的双重调用的惩罚。

【问题讨论】:

  • emplace 也可以,但是它将插入点之后的元素向后移动一个槽。
  • 简单的v[i] = std::move(value)怎么样?
  • @David Haim 在下面提到,该问题的假设是未定义所述运算符。应该在帖子中提到...将编辑

标签: c++ vector stl move-semantics c++17


【解决方案1】:

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 或移动赋值的一个很好的理由是它本质上是异常安全的。移动赋值运算符也将有益于其他容器操作。

【讨论】:

  • 啊,这就是我一直在寻找的答案......我还应该明确提到假设缺少移动赋值运算符。但是我确实有一个问题:假设 move ctor 是 noexcept 新的 throw 怎么可能?除了 oom 错误...但这些在正常情况下往往不会发生并且无论如何都无法恢复。
  • 如果你没有移动赋值操作符,那么涉及赋值的容器操作将使用复制赋值(如果不存在则编译失败)
  • 啊...非易失性:p。另外我认为 ptr = new T(std::move(value)) 可能是更正常的语法?两者有什么区别吗?我什至不知道您使用的语法是有效的 cpp tbh...
  • @George 您的建议将分配存储空间并创建一个与容器无关的对象。语法new(p)表示在存储中创建一个已经存在于p指向的位置的对象,p-&gt;~T();表示销毁一个对象而不释放其存储
  • 哦,很公平......这回答了我的下一个问题,即“这不会破坏数据局部性吗?” :P
猜你喜欢
  • 2011-01-09
  • 2013-12-29
  • 2017-09-10
  • 1970-01-01
  • 2023-03-26
  • 2015-01-09
  • 2011-01-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多