C++ 重复使用移动的容器?

C++ 重复使用移动的容器?,c++,c++11,move-semantics,C++,C++11,Move Semantics,重新使用移动的容器的正确方法是什么 std::vector<int> container; container.push_back(1); auto container2 = std::move(container); // ver1: Do nothing //container2.clear(); // ver2: "Reset" container = std::vector<int>() // ver3: Reinitialize container.push

重新使用移动的容器的正确方法是什么

std::vector<int> container;
container.push_back(1);
auto container2 = std::move(container);

// ver1: Do nothing
//container2.clear(); // ver2: "Reset"
container = std::vector<int>() // ver3: Reinitialize

container.push_back(2);
assert(container.size() == 1 && container.front() == 2);
std::向量容器;
容器。推回(1);
自动容器2=标准::移动(容器);
//ver1:什么也不做
//container2.clear();//第2版:“重置”
container=std::vector()//版本3:重新初始化
容器。推回(2);
断言(container.size()==1&&container.front()==2);
从我在C++0x标准草案中读到的内容;ver3似乎是正确的方式,因为移动后的对象处于

“除非另有规定,从物体上移开的物品应放置在 处于有效但未指定的状态。”

我从来没有发现任何“另有规定”的情况

虽然我觉得ver3有点迂回,我更喜欢ver1,虽然vec3可以允许一些额外的优化,但另一方面也很容易导致错误


我的假设正确吗?

我不认为你能对一个从对象中移出的对象做任何事情(除了销毁它)


您不能使用
交换
来获得移动的所有好处,但将容器保持在已知状态吗?

来自规范第17.3.26节“有效但未指定的状态”:

未指定的对象状态,除非满足对象的不变量,并且对象上的操作按照其类型指定的方式进行[例如:如果类型为
std::vector
的对象
x
处于有效但未指定的状态,
x.empty()
无条件调用,并且只有当
x.empty()
返回false时才能调用
x.front()
。-结束示例]

因此,对象是活动的。可以执行不需要先决条件的任何操作(除非先验证先决条件)


例如,
clear
没有任何先决条件。它会将对象返回到已知状态。因此,只需将其清除并正常使用。

对象处于有效但未定义的状态基本上意味着,虽然对象的确切状态无法保证,但它是有效的,因此成员函数(或非成员函数)只要不依赖具有特定状态的对象,就可以保证工作

clear()
成员函数对对象的状态没有任何先决条件(当然,除了它是有效的),因此可以在从对象移动时调用它。另一方面,例如
front()
依赖于容器不是空的,因此不能调用,因为不能保证它是非空的



因此,ver2和ver3都应该可以

你可以直接调用
clear
,因为它没有任何先决条件(因此不依赖对象的状态)。@Nicol:假设有一个
std::vector
实现,它存储了一个指向其大小的指针(看似愚蠢,但合法)。从该向量移动可能会使指针为空,之后
clear
将失败
operator=
也可能失败。@Ben:我认为这会违反“有效但未指定”的“有效”部分。@ildjarn:我认为这只是意味着运行析构函数是安全的。我想问题是什么是“有效”?+1。交换是一个好主意,虽然它不会在所有情况下都起作用,例如,使用自动将不起作用。也许一个在内部使用swap的安全移动是个好主意?它是一个活动对象,您可以使用任何没有前提条件的函数(除了不变量)
std::swap
的主模板有两个移动赋值,这些赋值的目标从值移动。这算作“对从对象移动的对象做点什么”,意味着向量永远是空的,但一般情况下并非如此,(即数组)“向量永远是空的”,这是基于什么的?@ronag:我的意思当然是ver2和ver3(从文本中应该很清楚,有趣的是,
front()的先决条件已经修复)
仅针对
std::array
,表中甚至没有说明。@Ben:§23.2.3表100说明
front()
的操作语义是
*a.begin()
,§23.2.1/6说明“如果容器是空的,那么
begin()==end()
”,而§24.2.1/5则说明“库从不假定过去的结束值是可取消引用的。”。因此,我认为可以推断
front()
的前提条件,尽管它肯定可以更清楚地说明。在标准中,我可以在哪里阅读“前提条件”“例如,对于std::vector方法?@ronag:§23.2包含列出这些方法的表。我发现以下内容很有趣,它们写“容器可以“比空的更空”。@ronag:1)如果容器处于有效状态,则调用
clear
是有效的。2) 当容器处于未指定状态时,调用
clear
会将容器置于指定状态,因为它在标准中规定了后条件(§23.2.3表100)
std::vector
有一个类不变量,
push_back()
总是有效的(只要
T
CopyInsertable
)。@ronag:open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3241.html引用了国家机构关于“空大于空”的一条评论。国家机构的评论是不正确的。N3241没有提出这样一个国家。如果std::container的实现确实有一个“比空更空”的状态,该状态必须是有效状态(即,您可以对该对象执行任何不需要先决条件的操作)。