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

Posted

技术标签:

【中文标题】在 std::unique 之后重新排列向量元素【英文标题】:Rearranged vector elements after std::unique 【发布时间】:2021-11-16 23:54:58 【问题描述】:

我目前正在阅读 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 );

【问题讨论】:

这并没有解决问题,但是sentence可以直接用std::vector&lt;std::string&gt; sentence(argv + 1, argv + argc);初始化。 【参考方案1】:

std::unique 是一个破坏性的过程。引用cppreference,

删除是通过移动范围内的元素以覆盖要删除的元素来完成的。

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

注释部分也注明了这一点:

[r, last)(如果有)中的迭代器,其中r 是返回值,仍然是可取消引用的,但元素本身具有未指定的值。调用unique 之后通常会调用容器的erase 成员函数,该函数会删除未指定的值并减小容器的物理大小以匹配其新的逻辑大小。

【讨论】:

很好的答案,这被称为“擦除删除习语”,它很常见,它有自己的***条目。 en.wikipedia.org/wiki/Erase%E2%80%93remove_idiom【参考方案2】:

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

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

您将看到以下输出:

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

【讨论】:

以上是关于在 std::unique 之后重新排列向量元素的主要内容,如果未能解决你的问题,请参考以下文章

去重函数unique,sort,erase的应用

std::unique

std::unique()函数(转)

排序多个线程如何在 std::condition_variable::notify_all 之后重新获取 std::unique_lock<std::mutex>

使用带有 unique_ptr 向量的赋值运算符

用 unique_pointers 填充向量