首页 > 解决方案 > 为什么在带有向量c ++的for循环结束时会发生这种情况

问题描述

我想擦除向量中的重复元素;我使用for循环来检查向量中的下一个元素是否与迭代中的当前元素相同,如果为真则将其删除,但由于某种原因,它会删除最后一个元素而不相等。

这是我的代码:

#include <string>
#include <vector>
#include <iostream>

using namespace std;

template <typename T> vector<T> uniqueInOrder(const vector<T>& iterable){
    vector<T> coolestVector = iterable;
    for (int i = 0; i < coolestVector.size(); i++)
    {
        if (coolestVector[i] == coolestVector[i+1]){
            coolestVector.erase(coolestVector.begin()+i);
            i--;
        }
        /*for (int i = 0; i < coolestVector.size(); i++)
        {
            cout<<coolestVector[i]<<", ";
        }
        cout<<i<<", ";
        cout<<coolestVector.size();
        cout<<endl;*/
    }

    for (int i = 0; i < coolestVector.size(); i++)
    {
        cout<<coolestVector[i]<<endl;
    }
    
    return coolestVector;
}
vector<char> uniqueInOrder(const string& iterable){
    vector<char> coolVector = {};
    for (int i = 0; i < iterable.size(); i++)
    {
        coolVector.push_back(iterable[i]);
    }
    const vector<char> realVector = coolVector;
    uniqueInOrder(realVector);
}

int main(){
    const string test = "AAAABBBCCDAABBB";
    uniqueInOrder(test);
}

输出:

vector 0: A, A, A, B, B, B, C, C, D, A, A, B, B, B, iterator value -1, vector size 14
vector 0: A, A, B, B, B, C, C, D, A, A, B, B, B, iterator value -1, vector size 13
vector 0: A, B, B, B, C, C, D, A, A, B, B, B, iterator value -1, vector size 12
vector 1: A, B, B, B, C, C, D, A, A, B, B, B, iterator value 0, vector size 12
vector 1: A, B, B, C, C, D, A, A, B, B, B, iterator value 0, vector size 11
vector 1: A, B, C, C, D, A, A, B, B, B, iterator value 0, vector size 10
vector 2: A, B, C, C, D, A, A, B, B, B, iterator value 1, vector size 10
vector 2: A, B, C, D, A, A, B, B, B, iterator value 1, vector size 9
vector 3: A, B, C, D, A, A, B, B, B, iterator value 2, vector size 9
vector 4: A, B, C, D, A, A, B, B, B, iterator value 3, vector size 9
vector 4: A, B, C, D, A, B, B, B, iterator value 3, vector size 8
vector 5: A, B, C, D, A, B, B, B, iterator value 4, vector size 8
vector 5: A, B, C, D, A, B, B, iterator value 4, vector size 7
vector 5: A, B, C, D, A, B, iterator value 4, vector size 6
vector 5: A, B, C, D, A, iterator value 4, vector size 5
A
B
C
D
A

预期的:

A
B
C
D
A
B

标签: c++loopsfor-loopvectorstd

解决方案


我已将此与我之前的答案分开,因为之前的答案可以独立存在,我不希望它卷入因解释未定义行为而引起的潜在争议。

为什么程序总是删除最后一个元素?

正式地说,我们处于未定义行为的领域,所以一切皆有可能。但是,这种行为很可能会出现在所有发布版本中,但有两个警告。

  1. 删除了较早的元素。如果不应该删除任何元素(一个值得添加到测试套件的案例),那么行为是不可预测的,可能是崩溃,但很可能是预期的行为。
  2. 移动构造留下一个副本。对于像char. 对于 的向量,您可能不会看到这种行为std::string

当 a 中间的一个元素std::vector被擦除时,该元素之后的所有元素都会向下移动一个索引;它们被复制(或移动)到前面的元素。

A B B C D
  ^
  |-- erase this
A B B C D
  ^ ^ ^    <--- shift and copy (or move)
  B C D
A B C D D
      ^
      |-- Last element in the vector

请注意,擦除时不会释放空间。向量仍然拥有以前的内存D;只是从向量实现之外访问元素是未定义的行为。此外,该内存不太可能在发布版本中通过向量更改其位。因此,向量的末尾很可能是向量最后一个元素的副本,除非移动构造函数更改了它。

现在来了你的条件。当iis时coolestVector.size()-1,您检查向量 ( ) 的最后一个元素是否coolestVector[i]等于向量 ( ) 末尾之后的元素coolestVector[i+1]。发布版本不会验证索引是否有效,并且操作系统不关心内存中的该位置是否被访问,因此这种比较很可能会像人们天真地期望的那样进行。向量的最后一个元素是否等于复制它的对象?是的!OK,删除最后一个元素。

很可能在发布版本中,但不要依赖它。


推荐阅读