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

Rearranged vector elements after std::unique

我目前正在研究 Stanley Lippman 的 C++ Primer。第 10 章介绍了泛型算法。

例如 std::sortstd::uniquestd::vector 成员函数 erase 应用于删除向量中的重复元素。

为了查看矢量元素如何被 std::unique 重新排列,我尝试打印每个元素,结果发现并非所有元素都被打印出来。然而,调用 .size() 表明向量的大小如预期的那样没有变化。

编译程序后:

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,

Removing is done by shifting the elements in the range in such a way that elements to be erased are overwritten.

这意味着 std::unique 返回的新结束迭代器之后的任何元素都将处于有效但未指定的状态。它们不应该被访问,因为它们应该通过调用 erase.

从向量中删除

这个在注释部分也有注明:

Iterators in [r, last) (if any), where r is the return value, are still dereferenceable, but the elements themselves have unspecified values. A call to unique is typically followed by a call to a container's erase member function, which erases the unspecified values and reduces the physical size of the container to match its new logical size.

还有10个元素;只是其中一个被“移走了”。如果您更改打印循环以引用单词,则:

  for ( const auto &el : words )
    std::cout << "'" << el << "'" << " ";

您将看到以下输出:

'fox' 'jumps' 'over' 'quick' 'red' 'slow' 'the' 'turtle' 'the' ''