std::vector<T>::分配使用有效的子范围?

std::vector<T>::assign using a subrange valid?

我想将向量转换为该向量的子范围,例如通过删除第一个和最后一个值。 assign 成员函数的使用在此上下文中有效吗?

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

Cppreference 表示

All iterators, pointers and references to the elements of the container are invalidated. The past-the-end iterator is also invalidated.

然而,这种失效似乎直到 end of assign

才发生

为了安全起见,我可以使用以下内容,但它看起来更冗长:

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

您的 link 引用的 __invalidate_all_iterators 函数只是一个调试工具。它不会 "cause" 使迭代器失效;它有效地报告迭代器已因先前的操作而失效。可能是此调试工具可能无法捕获由此分配引起的错误。

assign的前提条件是迭代器不在同一个容器中。违反前提条件会导致未定义的行为。

标准报价(最新稿):

[sequence.reqmts] a.assign(i,j) Expects: T is Cpp17EmplaceConstructible into X from *i and assignable from *i. For vector, if the iterator does not meet the forward iterator requirements ([forward.iterators]), T is also Cpp17MoveInsertable into X. Neither i nor j are iterators into a.

您的安全选择是正确的。

如果你想避免重新分配(记住会有未使用的 space 留下),如果你想避免复制(这对复杂类型很重要,对 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());