我通过std :: algorithm学习,发现了唯一性,但是在实践自己的过程中,我发现输出结果不是我所期望的,或者我不应该像文档说明那样说:
从范围[first,last)的每个连续等效元素组中除去除第一个元素外的所有元素,并为该范围的新逻辑末尾返回一个end-the-end迭代器。
vector<int> val = { 5,3,3,3,4};
unique(val.begin(), val.end());
for (auto it = val.begin(); it != val.end(); ++it)
cout << *it << " ";
输出:5 3 4 3 4.不是应该返回:5 3 4 3 3。
我认为它需要首先进行排序,所以我这样做:
vector<int> val = { 5,3,3,3,4};
sort(val.begin(), val.end());
unique(val.begin(), val.end());
for (auto it = val.begin(); it != val.end(); ++it)
cout << *it << " ";
,输出为:3 4 5 4 5。
我发现这真的很奇怪。你们知道为什么吗?
答案 0 :(得分:2)
cppreference on std::unique
为您解答:
保留了其余元素的相对顺序,并且容器的物理大小未更改。指向范围的新逻辑端和物理端之间的元素的迭代器仍然是可取消引用的,但是元素本身具有未指定的值。通常,对unique的调用之后是对容器的擦除方法的调用,该方法将擦除未指定的值并减小容器的物理大小以匹配其新的逻辑大小。
因此,要真正擦除元素,还应该使用vector::erase
,链接页面提供了以下示例:
std::vector<int> v { 5, 3, 3, 3, 4 };
auto last = std::unique(v.begin(), v.end());
v.erase(last, v.end());
for (auto i : v)
cout << i << "\n";
现在输出
5
3
4
答案 1 :(得分:1)
请注意std :: unique
"returns a past-the-end iterator for the new logical end of the range"
因此,要查看新范围,请尝试:
auto new_end = std::unique(val.begin(), val.end());
for (auto it = val.begin(); it != new_end; ++it)
cout << *it << " ";
答案 2 :(得分:0)
您从std::unique
获得的唯一保证就是您的拼写:从开始迭代器到返回的结束迭代器的顺序已指定。没有指定容器中的备用值会发生什么,从返回的过去的迭代器开始,一直持续到原始序列的结束迭代器为止。
std::unique
合同中还有其他一些次要细节/保证/要点,但此处与它们无关。最重要的是,您对std::unique
唯一的期望是从开始迭代器到返回的新的结束迭代器的顺序,并且未指定原始容器中的任何剩余值。
您的观察结果与您使用移动语义的实现std::unique
一致,对于简单的int
来说,这等同于复制语义。因此,原始迭代器中的其余值是以前的副本。这是std::unique
的典型实现,但这不是必需的。