std :: vector <T> :: assign使用子范围有效吗?

dfr*_*ese 8 c++ undefined-behavior

我想将向量转换为该向量的子范围,例如通过删除第一个和最后一个值。在这种情况下使用assign成员函数是否有效?

std::vector<int> data = {1, 2, 3, 4};
data.assign(data.begin() + 1, data.end() - 1);
// data is hopefully {2, 3}
Run Code Online (Sandbox Code Playgroud)

Cppreference指出

对容器元素的所有迭代器,指针和引用均无效。过去的迭代器也无效。

但是,直到分配结束,这种无效似乎才发生。

为了安全起见,我可以采用以下内容,但似乎比较冗长:

std::vector<int> data = {1, 2, 3, 4};
data = std::vector<int>{data.begin() + 1, data.end() - 1};
// data is now {2, 3}
Run Code Online (Sandbox Code Playgroud)

eer*_*ika 11

__invalidate_all_iterators您的链接所引用的功能仅仅是调试工具。它不会“导致”迭代器失效;它不会导致迭代器失效。它有效地报告了迭代器已被先前的操作无效。可能是该调试工具可能未捕获到由该分配引起的错误。

前提条件是assign迭代器不能位于同一容器中。违反先决条件会导致不确定的行为。

标准报价(最新草案):

[sequence.reqmts] a.assign(i,j)期望:T是Cpp17Emplace,可从* i构造为X,并从* i分配。对于向量,如果迭代器不满足正向迭代器要求([forward.iterators]),则T也是Cpp17MoveInsertable,可以转换为X。i 和j都不是a的迭代器。

您的安全替代方法是正确的。

如果您要避免重新分配(请记住将剩下未使用的空间),并且要避免复制(这对复杂类型很重要,对无关紧要int),那么以下操作应该很有效:

int begin_offset = 1;
int end_offset = 1;
if (begin_offset)
    std::move(data.begin() + begin_offset, data.end() - end_offset, data.begin());
data.erase(data.end() - end_offset - begin_offset, data.end());
Run Code Online (Sandbox Code Playgroud)