命名空间
变体
操作

std::unique_copy

来自 cppreference.cn
< cpp‎ | algorithm
 
 
算法库
约束算法和范围上的算法 (C++20)
约束算法,例如 ranges::copy, ranges::sort, ...
执行策略 (C++17)
排序和相关操作
划分操作
排序操作
二分搜索操作
(在已划分范围上)
集合操作 (在已排序范围上)
合并操作 (在已排序范围上)
堆操作
最小/最大操作
(C++11)
(C++17)
字典序比较操作
排列操作
C 库
数值操作
未初始化内存上的操作
 
定义于头文件 <algorithm>
template< class InputIt, class OutputIt >
OutputIt unique_copy( InputIt first, InputIt last, OutputIt d_first );
(1) (constexpr 自 C++20 起)
template< class ExecutionPolicy, class ForwardIt1, class ForwardIt2 >

ForwardIt2 unique_copy( ExecutionPolicy&& policy, ForwardIt1 first,

                        ForwardIt1 last, ForwardIt2 d_first );
(2) (自 C++17 起)
template< class InputIt, class OutputIt, class BinaryPred >

OutputIt unique_copy( InputIt first, InputIt last,

                      OutputIt d_first, BinaryPred p );
(3) (constexpr 自 C++20 起)
template< class ExecutionPolicy, class ForwardIt1,

          class ForwardIt2, class BinaryPred >
ForwardIt2 unique_copy( ExecutionPolicy&& policy,
                        ForwardIt1 first, ForwardIt1 last,

                        ForwardIt2 d_first, BinaryPred p );
(4) (自 C++17 起)

将范围 [firstlast) 中的元素复制到以 d_first 开头的另一个范围,使得没有连续相等的元素。只复制每组相等元素中的第一个元素。

1) 元素使用 operator== 进行比较。
如果 operator== 没有建立等价关系,则行为未定义。
3) 元素使用给定的二元谓词 p 进行比较。
如果 p 没有建立等价关系,则行为未定义。
2,4)(1,3) 相同,但根据 policy 执行。
只有当满足以下所有条件时,这些重载才参与重载决议

std::is_execution_policy_v<std::decay_t<ExecutionPolicy>>true

(直到 C++20)

std::is_execution_policy_v<std::remove_cvref_t<ExecutionPolicy>>true

(自 C++20 起)

如果 *d_first = *first 无效(直到 C++20)*first 不可写入d_first(自 C++20 起),则程序是非良构的。

如果源范围和目标范围重叠,则行为未定义。

给定 T 作为 InputIt 的值类型,如果重载 (1)(3) 满足以下所有条件,则行为未定义

(直到 C++20)
(自 C++20 起)

内容

[编辑] 参数

first, last - 定义要处理的元素范围的迭代器对
d_first - 目标范围的起始位置
policy - 要使用的执行策略
p - 二元谓词,如果元素应被视作相等则返回 ​true

谓词函数的签名应等价于以下形式

 bool pred(const Type1 &a, const Type2 &b);

虽然签名不需要有 const &,但函数不得修改传递给它的对象,并且必须能够接受类型(可能是 const)Type1Type2 的所有值,而与值类别无关(因此,不允许使用 Type1 &,除非对于 Type1,移动等同于复制 (自 C++11 起)(since C++11))。
类型 Type1Type2 必须使得类型为 InputIt 的对象可以被解引用,然后隐式转换为这两种类型。 ​

类型要求
-
InputIt 必须满足 LegacyInputIterator 的要求。
-
OutputIt 必须满足 LegacyOutputIterator 的要求。
-
ForwardIt1, ForwardIt2 必须满足 LegacyForwardIterator 的要求。

[编辑] 返回值

指向最后写入元素之后位置的输出迭代器。

[编辑] 复杂度

给定 Nstd::distance(first, last)

1,2) 精确地进行 max(0,N-1) 次使用 operator== 的比较。
3,4) 精确地应用 max(0,N-1) 次谓词 p

对于重载 (2,4),如果 ForwardIt1 的值类型既不是 CopyConstructible 也不是 CopyAssignable,则可能存在性能成本。

[编辑] 异常

具有名为 ExecutionPolicy 的模板参数的重载按如下方式报告错误

  • 如果作为算法一部分调用的函数的执行抛出异常,并且 ExecutionPolicy标准策略之一,则调用 std::terminate。对于任何其他 ExecutionPolicy,行为是实现定义的。
  • 如果算法无法分配内存,则抛出 std::bad_alloc

[编辑] 可能的实现

另请参阅 libstdc++libc++ 中的实现。

[编辑] 注解

如果 InputIt 满足 LegacyForwardIterator,此函数会重新读取输入以检测重复项。

否则,如果 OutputIt 满足 LegacyForwardIterator,并且 InputIt 的值类型与 OutputIt 的值类型相同,则此函数会将 *d_first*first 进行比较。

否则,此函数会将 *first 与本地元素副本进行比较。

[编辑] 示例

#include <algorithm>
#include <iostream>
#include <iterator>
#include <string>
 
int main()
{
    std::string s1 {"A string with mmmany letters!"};
    std::cout << "Before: " << s1 << '\n';
 
    std::string s2;
    std::unique_copy(s1.begin(), s1.end(), std::back_inserter(s2),
                     [](char c1, char c2) { return c1 == 'm' && 'm' == c2; });
 
    std::cout << "After:  " << s2 << '\n';
}

输出

Before: A string with mmmany letters!
After:  A string with many letters!

[编辑] 缺陷报告

以下行为变更缺陷报告被追溯应用于先前发布的 C++ 标准。

DR 应用于 已发布行为 正确行为
LWG 239 C++98 谓词被应用了 std::distance(first, last) 应用次数少一次 (对于非空范围)
(对于非空范围)
LWG 241 C++98 InputIt 的值类型不需要是 CopyConstructible 有条件地要求
LWG 538 C++98 InputIt 的值类型不需要是 CopyAssignable 有条件地要求
LWG 2439 C++98 InputIt 的值类型不需要是
CopyConstructible 如果 OutputItLegacyForwardIterator
有条件地要求

[编辑] 参见

adjacent_find
(函数模板) [编辑]
unique
(函数模板) [编辑]
copy
(函数模板) [编辑]
(算法函数对象)[编辑]
ranges::unique_copy