std::unique
| Defined in header <algorithm>
|
||
template< class ForwardIt >
ForwardIt unique( ForwardIt first, ForwardIt last );
|
(1) | (constexpr since C++20) |
template< class ForwardIt, class BinaryPred >
ForwardIt unique( ForwardIt first, ForwardIt last, BinaryPred p );
|
(2) | (constexpr since C++20) |
template< class ExecutionPolicy, class ForwardIt >
ForwardIt unique( ExecutionPolicy&& policy,
ForwardIt first, ForwardIt last );
|
(3) | (since C++17) |
template< class ExecutionPolicy, class ForwardIt, class BinaryPred >
ForwardIt unique( ExecutionPolicy&& policy,
ForwardIt first, ForwardIt last, BinaryPred p );
|
(4) | (since C++17) |
Removes all except the first element from every group of consecutive equivalent elements from the target range [first, last).
operator==.operator== does not establish an equivalence relation, the behavior is undefined.p.p does not establish an equivalence relation, the behavior is undefined.policy.true:
|
|
(until C++20) |
|
|
(since C++20) |
Removing is done by partitioning the elements in the target range. Given the partition point result, the leading elements of every group appear in [first, result), while other elements can only appear in [result, last).
- The underlying sequence of the target range is not shortened by the removing operation.
- Elements are shifted by copy assignment(until C++11)move assignment(since C++11).
- All iterators in
[result,last)are still dereferenceable, and each element of[result,last)has a valid but unspecified state(since C++11). - The removing operation is stable: the relative order of the elements not to be removed stays the same.
|
If the value type of |
(until C++11) |
|
If the type of |
(since C++11) |
Parameters
| first, last | - | the pair of iterators defining the target range |
| p | - | binary predicate which returns true if the elements should be treated as equal. The signature of the predicate function should be equivalent to the following:
While the signature does not need to have |
| policy | - | the execution policy to use |
| Type requirements | ||
-ForwardIt must meet the requirements of LegacyForwardIterator.
| ||
Return value
The iterator result mentioned above.
Complexity
Given \(\scriptsize N\)N as std::distance(first, last):
operator==.p.operator==.p.Exceptions
- If the temporary memory resources required for parallelization are not available, std::bad_alloc is thrown.
- If an uncaught exception is thrown while accessing objects via an algorithm argument, the behavior is determined by the execution policy (for standard policies, std::terminate is invoked).
Notes
A call to unique is typically followed by a call to a container's erase member function to actually remove elements from the container.
Possible implementation
See also the implementations in libstdc++, libc++, and MSVC STL.
| unique (1) |
|---|
template<class ForwardIt>
ForwardIt unique(ForwardIt first, ForwardIt last)
{
if (first == last)
return last;
ForwardIt result = first;
while (++first != last)
if (!(*result == *first) && ++result != first)
*result = std::move(*first);
return ++result;
}
|
| unique (2) |
template<class ForwardIt, class BinaryPredicate>
ForwardIt unique(ForwardIt first, ForwardIt last, BinaryPredicate p)
{
if (first == last)
return last;
ForwardIt result = first;
while (++first != last)
if (!p(*result, *first) && ++result != first)
*result = std::move(*first);
return ++result;
}
|
Example
#include <algorithm>
#include <iostream>
#include <vector>
int main()
{
// a vector containing several duplicate elements
std::vector<int> v{1, 2, 1, 1, 3, 3, 3, 4, 5, 4};
auto print = [&](int id)
{
std::cout << "@" << id << ": ";
for (int i : v)
std::cout << i << ' ';
std::cout << '\n';
};
print(1);
// remove consecutive (adjacent) duplicates
auto last = std::unique(v.begin(), v.end());
// v now holds {1 2 1 3 4 5 4 x x x}, where x is indeterminate
v.erase(last, v.end());
print(2);
// sort followed by unique, to remove all duplicates
std::sort(v.begin(), v.end()); // {1 1 2 3 4 4 5}
print(3);
last = std::unique(v.begin(), v.end());
// v now holds {1 2 3 4 5 x x}, where x is indeterminate
v.erase(last, v.end());
print(4);
}
Output:
@1: 1 2 1 1 3 3 3 4 5 4
@2: 1 2 1 3 4 5 4
@3: 1 1 2 3 4 4 5
@4: 1 2 3 4 5
Defect reports
The following behavior-changing defect reports were applied retroactively to previously published C++ standards.
| DR | Applied to | Behavior as published | Correct behavior |
|---|---|---|---|
| LWG 202 | C++98 | the behavior was unclear if the elements are compared using a non-equivalence relation |
the behavior is undefined in this case |
See also
(C++20) |
removes consecutive duplicate elements in a range (algorithm function object) |
| finds the first two adjacent items that are equal (or satisfy a given predicate) (function template & algorithm function object) | |
(C++20) |
|
| creates a copy of some range of elements that contains no consecutive duplicates (function template & algorithm function object) | |
(C++20) |
|
| removes elements satisfying specific criteria (function template & algorithm function object) | |
(C++20)(C++20) |
|
| removes consecutive duplicate elements (public member function of std::list<T,Allocator>)
| |
| removes consecutive duplicate elements (public member function of std::forward_list<T,Allocator>)
| |
| removes consecutive duplicate elements (public member function of std::hive<T,Allocator>)
|