重用移动容器的正确方法是什么?
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);
Run Code Online (Sandbox Code Playgroud)
从我在C++ 0x标准草案中读到的内容; ver3似乎是正确的方法,因为移动后的对象在a中
"除非另有规定,否则此类移动物体应处于有效但未指明的状态."
我从来没有找到任何"以其他方式指定"的实例.
虽然我发现ver3有点回旋并且会有更多首选ver1,虽然vec3可以允许一些额外的优化,但另一方面很容易导致错误.
我的假设是否正确?
我试图理解移动语义的通用规则。特别是容器和包含的元素。
原因是我试图在所有权和迭代器失效的背景下理解移动。为此,我将经历一些复杂性不断增加的案例,涉及典型容器、通用包含类型T、通用g和f函数。(也许一个重要的额外细节是,f实际上可能会或可能不会执行移动操作,或者它可能在运行时是偶然的。)
这个想法是引入案例3,这是这个问题的核心。
首先是一个相当没有争议的案例,这是可以的:
std::vector<T> v(100, t);
f(std::move(v));
v = make_a_vector();
Run Code Online (Sandbox Code Playgroud)
然而,移动后使用可能是臭代码
std::vector<T> v(100, t);
f(std::move(v));
g(v);
Run Code Online (Sandbox Code Playgroud)
我想大多数人都同意上面的做法是不行的。规则是(据我所知)移动后的唯一操作应该是赋值。我认为这尤其是因为它没有记录(未定义但有效的状态)移出向量的状态是什么(或者即使它被移动了)。因此,充其量v是空的,最坏的v情况是未指定的状态,因此g可以在此范围内执行未指定的操作。
std::vector<T> v(100, t);
f(std::move(v));
v.resize(120);
Run Code Online (Sandbox Code Playgroud)
这是对的吗?这不是一项任务,但resize没有先决条件。(发现这个Can I resize a vector that was moving from?)
现在是真正棘手的情况。
std::vector<T> v(100);
h(std::make_move_iterator(v.begin()), std::make_move_iterator(v.end()));
v.resize(120);
Run Code Online (Sandbox Code Playgroud)
(这里,h是一个采用迭代器的函数,假设它隐式引用 range 。 [iterator1, iterator2))
这是正确的代码吗?原因是.resize似乎要播放、移动、交换和复制类型为移出的对象T。
总而言之,调整其元素已(可能)移出的向量的大小是否正确?
编辑:为了论证,让我们指定函数的签名,以防它们与答案相关:
template<class …Run Code Online (Sandbox Code Playgroud)