移动后是否需要重置std :: list?

时间:2018-10-08 07:10:58

标签: c++ c++11

我有以下代码:

std::list some_data;
...
std::list new_data = std::move(some_data);
some_data.clear();
...

问题是some_data.clear()是否必要? (记录下来,some_data将来会被重用)

5 个答案:

答案 0 :(得分:7)

是的,这是必需的。

只有将std智能指针从中移出后,才能保证其处于默认构造状态。

容器处于有效但未指定的状态。这意味着您只能在没有前提条件的情况下调用成员函数,例如clear,使对象处于完全已知的状态。

答案 1 :(得分:4)

标准(N4713)的工作草案规定了对象从以下位置移出后的状态:

  

20.5.5.15库类型[lib.types.movedfrom]的移出状态
  1可以移出C ++标准库中定义的类型的对象。移动操作可以显式指定或隐式生成。 除非另有说明,否则此类移出的对象应置于有效但未指定的状态。

     

20.3.25 [defns.valid]
  未指定对象的有效但未指定状态值,除了满足对象的不变性并且对该对象的操作按其类型指定的操作

您可以对移出的容器安全地执行的唯一操作是不需要先决条件的操作。 clear没有任何先决条件。它将使对象返回到已知状态,可以从该状态再次使用。

答案 2 :(得分:2)

否,不需要 清除列表。这样做既合理又方便。

该列表将包含N个元素,每个元素都具有未指定的值,其中N≥0。因此,如果您想重新填充列表,则理论上可以分配给保留的元素,而不是清除它们,然后从头开始重新插入所有内容。

当然,N≠0的可能性很小,因此在实践中清除是正确的选择。

答案 3 :(得分:0)

它取决于您“重用”的含义。有很多重用可以完全定义对象的状态,而与对象的先前状态无关。

显而易见的是,分配给移动对象,这发生在天真的交换中

template <typename T>
void swap(T& lhs, T& rhs)
{
    T temp = std::move(lhs);
    lhs = std::move(rhs); // lhs is moved-from, but we don't care.
    rhs = std::move(temp); // rhs is moved-from, but we don't care.
}

如果您想通过调用some_data.push_back“重用”,那么可以,请先clear将其

答案 4 :(得分:0)

简短答案:
是的,您应该清除它,因为该标准并未明确定义移动后源列表的状态。
此外,在容器从容器移出后重用时始终调用clear()是一个简单的规则,即使有多余的容器也不会造成任何重大开销。

更长的答案:
正如我在一些评论中提到的,我无法想象任何合法且明智的实现,在将其用作移动构造函数的源之后,源std::list只能是空的std::list(感谢@ Lightness在Orbit中竞赛以挖掘标准)。移动构造必须在线性时间内进行,这不允许任何按对象操作,并且AFAIK也不允许其具有较小的固定大小的就地缓冲区,该缓冲区可能是对象中剩余的“僵尸”元素的来源。来源清单。

但是,即使您可以跟踪标准中的所有内容,您仍然必须在每次省略代码中的clear()时都要记录在案,并要警惕有人通过替换{ {1}}使用本地容器,无法完全满足标准中的要求(例如,利用小型缓冲区优化)。另外,前一条语句仅对构造有效。进行moveassignment时,从容器中移出绝对是不可能的。

总结:即使在这种特殊情况下不使用std::list在技术上是正确的,这样做也不值得您费神费力(如果您处在值得这样做的环境中,您可能正在将代码调整为标准库的特定版本,而不是标准文件)。