Reputation: 6616
For this code:
std::vector<int> v = {...};
std::sort(v.begin(), v.end());
// Does this work?
std::size_t unique_count = std::unique(v.begin(), v.end()) - v.cbegin();
In the last line, I think since std::unique
just moves stuffs around inside the vector and does not insert anything into it, no iterators should be invalidated, and so the way I'm calculating unique_count
should be correct. But I want to make sure that is the case. Is it?
Upvotes: 1
Views: 219
Reputation: 719
std::unique
return an iterator to one position past the last 'unique' element in the container.
auto last = std::unique(v.begin(), v.end());
Then the range [last
, v.end()
) contains whatever, you can't rely on v.cbegin()
. Instead:
auto unique_count = std::distance(v.begin(), last);
will do the trick.
http://en.cppreference.com/w/cpp/algorithm/unique
Upvotes: 3
Reputation: 69882
std::unique
is an algorithm. All stl algorithms operate on ranges, not containers.
Although the algorithm may swap element contents, the iterators to those elements remain unchanged.
This is a guarantee.
If it were not, then this could not work:
#include <algorithm>
#include <vector>
#include <iostream>
#include <array>
int main()
{
auto unique_size = [](auto&& container)
{
std::sort(std::begin(container), std::end(container));
return std::unique(std::begin(container), std::end(container)) - std::cbegin(container);
};
std::cout << unique_size(std::vector<int> {6,5,4,4,3,2,1}) << std::endl;
std::cout << unique_size(std::array<int,7> {6,5,4,4,3,2,1}) << std::endl;
int x[] = {6,5,4,4,3,2,1};
std::cout << unique_size(x) << std::endl;
// Does this work? yes.
}
mandated output:
6
6
6
Upvotes: 5