我找不到更好的标题,如果需要,请根据下面的问题进行更新。
考虑一个迭代器-iter
,它指向std::vector<int>
中的元素。我使用在当前迭代器位置插入*iter
的值
iter = target.insert(iter, *iter);
我知道insert
会将迭代器返回到新插入的元素。现在我把上面的声明改为:
iter = target.insert(iter, *iter++);
我知道这会表现得很尴尬,并导致分段错误。我不能理解的是,如何评估上述作业?我的意思是,iter
在该赋值之后将指向哪个元素。据我所知,由于我使用了后增量运算符,它的行为应该与第一条语句类似,我从下面的示例赋值中推断出:
i = i++;
由于上述赋值不会影响i
的值,因此*iter++
的情况也应如此。
幕后的实际行为是什么?
这是真正的代码:
std::vector<int>::iterator begin = target.begin();
while (begin != target.end()) {
if (*begin % 2 == 0) {
begin = target.erase(begin);
} else {
begin = target.insert(begin, *begin); // I changed this line
begin += 2;
}
}
基本上,上面的代码是从向量中删除偶数元素,并复制奇数元素。
编辑:
好的,如果我将第二行更改为++begin
,除了之前的更改之外,它的工作方式与当前代码相同。因此,我用以下行替换了else
块中的两行:
begin = target.insert(begin, *begin++);
++begin;
因此,它似乎比前一种情况下给迭代器分配了一个过去。
所以,这就是我从这种行为中理解的:
*begin++
首先去引用begin
以获得当前位置的值begin
后递增insert
现在在后增量之后的迭代器之前插入未引用的值。因此,它不是在原始begin
之前插入,而是在++begin
之前插入。然后返回其插入的值++begin
我解释对了吗?
我不太理解你的问题,但为了回应你列出的理解:你的理解在特定的编译器/day/build上可能是正确的。未指定是在begin
还是begin + 1
处插入(这会导致从insert
返回的值是两个不同的可能值之一),因为编译器可以按其喜欢的任何顺序评估insert
的参数。与其试图准确地计算出会发生什么,不如将代码分割成适当的部分,使其完全清楚地表明您要做什么,并让优化器为您处理事情。几乎可以肯定的是,它被核心转储的原因是,当你增加2时,你会跳过end
,永远不会检测到你已经通过了容器的末尾。
我觉得我还应该指出,"幸运的是"在函数参数的求值之后有一个序列点,或者begin = target.insert(begin, *begin++);
将是未定义的行为,对begin
进行两次写入,并且没有插入序列点(例如i = i++
是UB)。
AFAIK您构造的target.insert(iter,*iter++)不是合法的c++,因为它会导致"未定义的行为"*iter++是合法的,从左到右计算,但没有指定函数调用的agruments的计算顺序。编写这样的表达式是一个编程错误。
准确地说,你的代码
target.insert(iter, *iter++)
给定别名
std::vector<int>::iterator cur = iter;
std::vector<int>::iterator next = iter + 1;
可以通过以下两种方式评估
targets.insert(next, *cur);
++iter;
或
targets.insert(cur, *cur);
++iter;
确切的版本取决于编译器、操作系统、其他代码等,通常不会指定。
虽然这是一个非常古老的问题,但我想分享我的观点,欢迎讨论。
target.insert(iter, *iter++)
该代码将对产生一些影响
*iter++
:获取值*iter
,将来调用iter++
- 将CCD_ 28插入向量
但插入值对矢量可能有不同的影响取决于大小是否等于容量
如果size == capacity
,向量需要malloc新内存并复制到新内存,因此迭代器需要更新
如果是size < capacity
,矢量直接插入项。
因此返回并关注代码iter = target.insert(iter, *iter++);
如果插入导致新内存,则使用iter++
将访问无效地址并导致分段错误。
如果你写这样的代码:iter = target.insert(iter, *iter);
,iter会一直更新,所以它是正确的
因此,如果您确信插入后大小总是小于容量,则可以使用此代码,但不建议使用