移动后是否需要重置标准::列表?



我有以下代码:

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

问题是some_data.clear()是否有必要?(作为记录,some_data将来会重复使用(

是的,这是必要的。

只有 std 智能指针在从移出后保证处于默认构造状态。

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

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

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

20.3.25 [defns.valid]
未指定的对象的有效但未指定的状态值,除非满足对象的不变量并且对象上的操作的行为符合为其类型指定的状态

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

不,没有必要清除列表。这样做是合理和方便的。

该列表将有 N 个元素,每个元素都采用一个未指定的值,用于某些 N≥0。因此,如果要重新填充列表,理论上可以分配给保留而不是清除的元素,然后从头开始重新插入所有内容。

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

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

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

但是,即使您可以在标准中追踪所有这些内容,您仍然必须记录每次省略代码中的clear()时,并警惕有人通过用自行开发的容器替换std::list来重构代码,这并不能完全满足标准中的要求(例如,利用小缓冲区优化(。此外,前面的语句仅对移动构造有效。在移动分配中,从容器中移出的绝对有可能不是空的。

总结:即使在这种特殊情况下不使用clear在技术上是正确的,恕我直言,这样做是不值得的(如果你在一个值得的环境中,你可能会调整你的代码到标准库的特定版本,而不是标准文档(。

这取决于你所说的"重用"是什么意思。有许多重用完全定义了对象的状态,而不考虑其以前的状态。

显而易见的是分配给一个移自对象,这发生在朴素交换中

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

最新更新