在std::unique之后重新排列vector元素



我目前正在阅读Stanley Lippman的c++ Primer。第10章介绍了泛型算法。

std::sortstd::uniquestd::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' ''

最新更新