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?
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
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
Related
While learning remove-erase idiom, as well as understanding how std::min_element() work How to use std::min_element in C++17?. I thought to try removing minimum element from the following piece of code:
#include <algorithm>
#include <iostream>
#include <vector>
int main()
{
std::vector<int> v{3, 1, 4, 1, 5, 9};
std::vector<int>::iterator result = std::min_element(v.begin(), v.end());
std::cout << "min element at: " << std::distance(v.begin(), result);
}
There are two minimum elements in v. I tried to remove both of them with added diagnostics
int main()
{
std::vector<int> v{3, 1, 4, 1, 5, 9};
std::vector<int>::iterator result = std::min_element(v.begin(), v.end());
v.erase(result); // This removes just one minimum. What if need to remove all?
v.push_back(1); // Okay, let's add the minimum again
std::vector<int>::iterator another_result = std::min_element(v.begin(), v.end());
std::cout << "min element: " << *another_result << std::endl;
auto iter = std::remove(std::begin(v), std::end(v), *another_result);
// If I write 1 instead of *another_result, I manage to remove all 1's. No need to use iter-1 in erase idiom then.
std::cout << "\nWhere is my iterator pointing? It is at: " << std::distance(v.begin(), iter);
v.erase(iter, std::end(v)); // All the minimum are gone if I use iter-1 instead of iter and use *another_result
std::for_each(v.begin(), v.end(), [](const int& x){std::cout << x << " ";}); // Why is still "1" there?
}
link
My questions are, as highlighted in the code with the comments,
Why I am able to remove all the instances of minimum by providing a literal but not a de-referenced iterator? i.e.
Why does the following work?
auto iter = std::remove(std::begin(v), std::end(v), 1);
However,
If I choose to stick with a de-reference iterator,
auto iter = std::remove(std::begin(v), std::end(v), *another_result);
Doesn't remove all the instances of minimum while sticking to remove-erase idiom.
It looks like you are comparing with a reference into the vector. The element you passed in then gets moved by remove and when comparing against it a second time the reference observes some other value.
This works just fine:
int by_value = *another_result;
auto iter = std::remove(std::begin(v), std::end(v), by_value);
The third parameter of the std::remove overload you're using takes a const T&, but it's "invalidating" the reference in the process of doing its operation.
If you look at the "possible implementation" on en.cppreference
template< class ForwardIt, class T >
ForwardIt remove(ForwardIt first, ForwardIt last, const T& value)
{
first = std::find(first, last, value);
if (first != last)
for(ForwardIt i = first; ++i != last; )
if (!(*i == value))
*first++ = std::move(*i); //here it changes the value that "value" points to
//if you are using a reference of an element inside the vector
return first;
}
This problem is also mentioned in the "Notes" section as:
Because std::remove takes value by reference, it can have unexpected
behavior if it is a reference to an element of the range [first,
last).
If you want to remove all the minimum values in one go, you could do something a little more odd like this:
template<class T>
void remove_min( std::vector<T> &container ) {
if ( container.empty() ) return;
T min_val = *std::min_element( container.begin(), container.end() );
container.erase( std::remove( container.begin(), container.end(), min_val ), container.end() );
}
Note that the min_val is a copy first (see PeterT's answer for explanation). The above can probably be modified to work with other containers.
Keep in mind that std::remove doesn't really remove anything. The return value from the function will point to after where the new last element would be, then call the container's erase method from there to remove all the elements from that point on.
For simplification of my question i will use std::string::iterator and std::string::reverse_iterator but the question is about iterators in general.
Is there any particular reason to iterate backwards using the following loop:
std::string s = "something";
for (std::string::reverse_iterator it = s.rbegin(); it != s.rend(); ++it)
rather than this one:
std::string s = "something";
std::string::iterator it = in.end();
while(it!=in.begin())
{
it--;
//do something
}
Reverse iterators allow you to reuse generic code because you can treat them like normal iterators, calling ++ to go backwards. For example:
#include <iostream>
#include <string>
template <class Iterator>
void printAll(Iterator begin, Iterator end)
{
for (auto it = begin; it != end; ++it) // ++ can mean "go backwards"
// if Iterator is a reverse
// iterator
{
std::cout << *it << "\n";
}
}
int main()
{
std::string s = "123";
printAll(s.begin(), s.end()); // prints 1, 2, 3
printAll(s.rbegin(), s.rend()); // prints 3, 2, 1
}
Notice how you do not need to write a reverse version for printAll using --.
Now, consider all the functions in <algorithm>. The existence of reverse iterators means that you can easily use all of them in a reverse manner. For example, there is std::copy_n, but not std::reverse_copy_n, but with reverse iterators, it's not necessary, because you can write something like this:
#include <iostream>
#include <string>
#include <algorithm>
#include <iterator>
int main()
{
std::string input = "abcdef";
std::string output;
std::string output_reversed;
// copy the first 3 elements:
std::copy_n(input.begin(), 3, std::back_inserter(output));
// copy the first 3 elements going backwards, starting at the last one:
std::copy_n(input.rbegin(), 3, std::back_inserter(output_reversed));
std::cout << output << "\n"; // prints abc
std::cout << output_reversed << "\n"; // prints fed
}
For non-generic code, such as in your question, it's more of a style issue, with few technically sound arguments to prefer one over the other.
Since begin() points to the first member, and end() points to the member next to the last, that is all about clean code (since in case of using not reverse iterators you would do iterator decrement first, then the code you want to execute, then you will compare iterator with begin(), but it is wrong, since begin() points to an existing first element.
std::vector::end() at cplusplus.com
Deleting the element 4th element in a vector requires the following code:
vector<int> v;
....
....
v.erase(v.begin()+3); // Erase v[3], i.e. the 4th element
I'm wondering why we need the v.begin() part.
It would be nicer just to write:
v.erase(3); // Erase v[3], i.e. the 4th element
The begin() is a member of vector so the erase method could just as well handle that part for us so that our code would be more readable and easy to understand.
There is probably a good reason and I like to know.
Can someone explain or link an explanation?
Thanks.
If this is something you'd like to be able to do, it's easy enough to come up with a function template (or is it a template function?) that will do this with a slightly different, but probably similar enough syntax:
#include <iostream>
#include <ostream>
#include <vector>
template <typename T>
void erase_at( T& container, size_t pos)
{
container.erase(container.begin() + pos);
}
using namespace std;
int main() {
vector<int> v;
v.push_back(0);
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
v.push_back(5);
for (vector<int>::iterator i = v.begin(); i != v.end(); ++i) {
cout << *i << " ";
}
cout << endl;
erase_at(v, 3); // <-- instead of `v.erase(v.begin() + 3)`
for (vector<int>::iterator i = v.begin(); i != v.end(); ++i) {
cout << *i << " ";
}
cout << endl;
return 0;
}
Presumably, one of the key things here is to create a uniform interface to the standard library containers.
Let's look at std::set<T>, std::vector<T>, and std::list<T>. In only one of these cases do we have access to a random access iterator. In all the other cases, getting container.begin() + 3 can be relatively expensive. Especially when the user probably has an iterator already, because they found the element exists in the object and they want to remove it.
Because of vector.erase receives iterator, but not integer.
You can see that on documentation http://www.cplusplus.com/reference/vector/vector/erase/
STL developers, I think, wanted to make unique interface of erasing on all container generic classes(vector, list, etc)
I have a list:
list<Student>* l;
and I would like to get an element at a specified index. Example:
l->get(4)//getting 4th element
Is there a function or method in list which enables it to do so?
std::list does not have a random access iterator, so you have to step 4 times from the front iterator. You can do this manually or with std::advance, or std::next in C++11, but bear in mind that both O(N) operations for a list.
#include <iterator>
#include <list>
....
std::list<Student> l; // look, no pointers!
auto l_front = l.begin();
std::advance(l_front, 4);
std::cout << *l_front << '\n';
Edit: The original question asked about vector too. This is now irrelevant, but may be informative nonetheless:
std::vector does have random access iterators, so you can perform the equivalent operation in O(1) via the std::advance, std::next if you have C++11 support, the [] operator, or the at() member function:
std::vector<Student> v = ...;
std::cout << v[4] << '\n'; // UB if v has less than 4 elements
std::cout << v.at(4) << '\n'; // throws if v has less than 4 elements
Here's a get() function that returns the _ith Student in _list.
Student get(list<Student> _list, int _i){
list<Student>::iterator it = _list.begin();
for(int i=0; i<_i; i++){
++it;
}
return *it;
}
If you want random access to elements, you should use a vector and then you can use [] operator to get the 4th element.
vector<Student> myvector (5); // initializes the vector with 5 elements`
myvector[3]; // gets the 4th element in the vector
For std::vector you can use
myVector.at(i) //retrieve ith element
I'm looking for a std container like a std::list that can efficiently move an element to the front:
a-b-c-d-e
move "b" to front:
a-c-d-e-b
There is no such function in the std containers. Therefor, I think I must combine a remove and push_front function but has anyone can find a better idea?
Thank in advance.
If you don't have to maintain the order of the other elements,
then the simplest solution is doubtlessly just to swap the
element you want with the first element in the container. This
will be efficient with all containers.
Otherwise, std::list offers a splice operation which could
be used. Something like the following, I think:
void
moveToFront(
std::list<MyType>& list,
std::list<MyType>::iterator element )
{
if ( element != list.begin() ) {
list.splice( list.begin(), list, element, std::next( element ) );
}
}
This should end up with only a couple of pointer operations, and
no copies. On the other hand, std::list can be very slow in
general (because of its poor locality); I'd measure very
carefully against the naïve implementation using std::vector,
to make sure it was a win globally. Eliminating all copies here
may not be a win if iterating to find the element you want to
move to the front is ten time more expensive. (A lot of this
depends on how expensive MyType is to copy, and how large it
is. If sizeof(MyType) is close to the size of a page, or
accessing MyType ends up accessing a lot of indirectly
allocated objects, the locality argument won't hold.)
With an std::vector, rather than the obvious erase/insert
void
moveToFront(
std::vector<MyType>& list,
std::vector<MyType>::iterator element )
{
MyType tmp( *element );
std::copy_backwards( list.begin(), std::prev( element ), element );
*list.begin() = tmp;
}
This will result in less copies than the erase (which copies
all of the following elements) insert (which also copies all
of the following elements—which means all of the elements,
because we are inserting at the beginning) pattern.
On std::vector, you could use std::rotate, which has linear complexity
#include <algorithm>
#include <iostream>
#include <iterator>
#include <vector>
std::vector<int> v = { 0, 1, 2, 3, 4 };
int main()
{
std::copy(v.begin(), v.end(), std::ostream_iterator<int>(std::cout, ","));
std::cout << "\n";
// swap ranges [1, 2) and [2, 5)
auto it = std::next(v.begin(), 1); // O(1)
auto rb = std::next(it);
auto re = v.end();
std::rotate(it, rb, re); // O(N)
std::copy(v.begin(), v.end(), std::ostream_iterator<int>(std::cout, ","));
std::cout << "\n";
}
On a std::list you could use the member function splice, which (given iterators) has constant complexity
#include <algorithm>
#include <iostream>
#include <iterator>
#include <list>
std::list<int> v = { 0, 1, 2, 3, 4 };
int main()
{
std::copy(v.begin(), v.end(), std::ostream_iterator<int>(std::cout, ","));
std::cout << "\n";
auto it = std::next(v.begin(), 1); // O(N)
auto rb = std::next(it);
auto re = v.end();
v.splice(it, v, rb, re); // O(1)
std::copy(v.begin(), v.end(), std::ostream_iterator<int>(std::cout, ","));
std::cout << "\n";
}
NOTE: the last element is conventially denoted as back in the STL containers, and the first element as front. For std::vector, getting iterators to a certain element is constant time, and swapping is linear time. For std::list, getting iterators is linear time, but splicing into the same list is constant time. However, the much better memory caching behavior of vector is also important as this benchmark by Stroustrup shows.
UPDATE: Several commenters mentioned simply swapping elements: this only applies if you want to transform a-b-c-d-e into a-e-c-d-b. In that case, use std::iter_swap on any container you like. For the transformation of a-b-c-d-e into a-c-d-e-b, use std::rotate or list::splice.