我目前正在阅读Stanley Lippman的c++ Primer。第10章介绍了泛型算法。
以std::sort
、std::unique
和std::vector
成员函数erase
为例,用于删除vector中的重复元素。
为了了解vector元素是如何通过std::unique重新排列的,我尝试打印每个元素,只是发现并不是所有元素都被打印出来。然而,对.size()
的调用告诉vector的大小如预期的那样保持不变。
程序编译完成后:
clang++ -std=c++11 -o elimDubs elimDubs.cc
和用
调用程序./elimDubs the quick red fox jumps over the slow red turtle
程序打印
Size after std::unique: 10
fox jumps over quick red slow the turtle the
是10个元素中的9个。(red
缺失)为什么?对于程序来说,这并不重要,因为随后调用erase
是为了删除重复的元素,但是仍然有元素丢失或至少没有被打印,这让我很恼火。
#include <vector>
#include <string>
#include <iostream>
#include <algorithm>
void elimDubs( std::vector<std::string> &words )
{
std::sort( words.begin(), words.end() );
auto end_unique = std::unique( words.begin(), words.end() );
std::cout << "Size after std::unique: "
<< words.size() << std::endl;
for ( const auto &el : words )
std::cout << el << " ";
std::cout << std::endl;
}
int main(int argc, char **argv)
{
std::vector<std::string> sentence;
if ( argc < 2 )
return -1;
std::copy( argv + 1, argv + argc,
std::back_inserter(sentence) );
elimDubs( sentence );
}
std::unique
是一个破坏性的过程。引用cppreference,
删除是通过移动范围内的元素来完成的,这样要删除的元素就会被覆盖。
这意味着std::unique
返回的新的end迭代器之后的任何元素都将处于有效但未指定的状态。它们不应该被访问,因为它们应该通过调用erase
从vector中移除。
这在注释部分也有说明:
[r, last)
(如果有)中的迭代器,其中r
是返回值,仍然是可解引用的,但元素本身具有未指定的值。在调用unique
之后,通常会调用容器的erase
成员函数,该函数会擦除未指定的值,并减小容器的物理大小以匹配新的逻辑大小。
仍然有10个元素;只是其中一个被"从"搬走了。如果将打印循环更改为引用单词,则如下:
for ( const auto &el : words )
std::cout << "'" << el << "'" << " ";
您将看到以下输出:
'fox' 'jumps' 'over' 'quick' 'red' 'slow' 'the' 'turtle' 'the' ''