Use of cbegin and cend in vector - c++

I want to observe the difference between cbegin and begin.
But when i use cbegin i am getting the same result as begin.
According to definition cbegin will return const itertaor and we cant modify the element using the const iterator returned by cbegin.
But, still i am able to erase the element at particular position.
for (auto i = g1.cbegin(); i != g1.cend(); ++i){
cout << *i << " ";
}
//below code erases element at const pointer
g1.erase(i);

The member function erase accepts const_iterator(s).
For example
iterator erase(const_iterator position);
In early Standards the function indeed was declared with non-constant iterators.
Take into account that the function returns a non-constant iterator but it can be converted implicitly to a constant iterator and can be compared with constant iterators.
By the way this call
g1.erase(i);
erases nothing because after the loop i is equal to the iterator returned by the function cend provided that the name i is defined before the loop.
auto i = g1.cbegin();
for (; i != g1.cend(); ++i){
cout << *i << " ";
}
//below code erases element at const pointer
g1.erase(i);
You can erase an element of the vector using the const_iterator because the vector itself is not constant. If the vector would be constant you could not erase its element.
That is the erase member function changes the vector itself (so it may not be applied to a constant vector), but it does not change elements of the vector using the const_iterator.

Thanks a lot Vlad from Moscow.
I just tried *i=3; in the loop where i am using cend and cbegin.
for (auto it = g1.cbegin(); it != g1.cend(); ++it){
cout << *it << " ";
*it=3;
}
I got compilation error :
error: assignment of read-only location ‘it.__gnu_cxx::__normal_iterator >::operator*()’
*it=3;
^

Related

Segmentation fault when erasing elements while iterating std::deque

Why does the following code crash? And what should I do when I am iterating via reverse iterator. How do I erase individual elements then?
deque q;
q.push_back(4);
q.push_back(41);
q.push_back(14);
for (auto it = q.begin(); it != q.end();) {
auto current = it;
q.erase(current);
it++;
}
Why does the following code crash ? How do I erase individual elements then ?
std::deque::erase invalidates iterators.
All iterators and references are invalidated, unless the erased elements are at the end or the beginning of the container, in which case only the iterators and references to the erased elements are invalidated.
The past-the-end iterator is also invalidated unless the erased elements are at the beginning of the container and the last element is not erased.
In your code, the iterators to the element to be erased (i.e. it and current) will become invalid after q.erase(current), then it++ will lead to UB.
You could make use of the return value of std::deque::erase
Iterator following the last removed element. If the iterator pos refers to the last element, the end() iterator is returned.
for (auto it = q.begin(); it!=q.end(); )
{
it = q.erase(it);
}
And what should I do if I am iterating via reverse iterator.
Because std::deque::erase doesn't accept reverse_iterator as parameters, you need to use base() to convert it to normal iterator (pay attention to the position conversion). Such as
for (auto it = q.rbegin(); it!=q.rend(); )
{
it = std::make_reverse_iterator(q.erase((++it).base()));
}
As per C++11 23.3.3.4 deque modifiers /4, deque iterators become invalid if you delete certain elements.
An erase operation that erases the last element of a deque invalidates only the past-the-end iterator and all iterators and references to the erased elements.
An erase operation that erases the first element of a deque but not the last element invalidates only the erased elements.
An erase operation that erases neither the first element nor the last element of a deque invalidates the past-the-end iterator and all iterators and references to all the elements of the deque.
In your case, you're usually only ever erasing the first element so it will only invalidate that element. That means the it++ is invalid and you should instead use something like:
it = q.erase(it);
inside the loop, since the erase call itself returns an "adjusted" iterator. This will also work when removing the last element.
However, since your code is totally clearing the list (assuming it's not a cut down version of something which needs to process each element), you can ditch the loop altogether and just use:
q.clear();
As the other answerers have already pointed out, erasing elements from the queue will invalidate the iterators you are using to iterate its elements. Thus it fails.
But I assume that you don't intend to erase all elements in the queue, in which case you probably would have rather used:
q.erase(q.begin(), q.end());
or
q.clear();
Therefore, I'd like to suggest using another technique, that can be used to delete items matching certain criteria from a queue: the erase-remove idiom.
Here, the functions std::remove(...) and std::remove_if(...) are used to move the items to be deleted (matching certain criteria) to the end of the container. The range-based version of q.erase(...) is then used to delete the items.
Here's an example:
#include <deque>
#include <algorithm>
#include <iostream>
// predicate function for removal of elements
bool greater_three(int x) {
return x > 3;
}
int main() {
std::deque<int> q = {1,2,3,4,5};
for (auto i : q) std::cout << i << " "; std::cout << "\n";
// delete all items with value 3
q.erase(std::remove(q.begin(), q.end(), 3), q.end());
for (auto i : q) std::cout << i << " "; std::cout << "\n";
// delete all items with value > 3
q.erase(std::remove_if(q.begin(), q.end(), greater_three), q.end());
for (auto i : q) std::cout << i << " "; std::cout << "\n";
}
The output is:
$ g++ test.cc -std=c++11 && ./a.out
1 2 3 4 5
1 2 4 5
1 2
For reference:
http://en.cppreference.com/w/cpp/container/deque/erase
http://en.cppreference.com/w/cpp/container/deque/clear
http://en.cppreference.com/w/cpp/algorithm/remove
q clearly doesn't support removing elements while iterating through them.

Incrementing iterator that is used as first and last of std::multimap erase range

While running an example that shows how to erase a range from std::map/multimap I have noticed strange behaviour in the following code:
#include <map>
#include <iostream>
#include <string>
int main()
{
std::multimap<int, std::string> myMap;
myMap.insert(std::make_pair(3, "three1"));
myMap.insert(std::make_pair(3, "three2"));
myMap.insert(std::make_pair(3, "three3"));
myMap.insert(std::make_pair(45, "fourty five"));
myMap.insert(std::make_pair(-1, "minus one"));
std::multimap<int, std::string>::iterator iter = myMap.find(3);
if (iter != myMap.end()) {
myMap.erase(iter, iter++); //segmentation fault(!)
}
for (auto element : myMap) {
std::cout << element.first << " -> " << element.second << std::endl;
}
return 0;
}
Which I build with command g++ --std=c++11 main.cpp (I use g++ 5.2.1).
Why post-incrementation of my iterator causes a Segmentation fault?
I would rather say that this should create 2 copies of this iterator, pass them into the erase method, "erase nothing" just as would code myMap.erase(iter, iter); and then increment the iter.
What logic stands behind this segfault?
Is this an invalid use of iter iterator? If so - why?
BTW.
It compiles when I use pre-incrementation myMap.erase(iter, ++iter) and here it "erase nothing" as I mentioned above.
The order of evaluation of the arguments to a function call is not defined. So when you write:
myMap.erase(iter, iter++); //segmentation fault(!)
the compiler is free to evaluate the second argument first, or not. As you use the same iterator, but have a side effect, you get Undefined Behaviour (refer to C++ standard, section 1.9/15).
For example, if the compiler evaluates first the second argument iter++, the incremented iterator would be used as the first argument, while second argument is not incremented iter. As a consequence: the range passed to erase() would be [std::next(iter), iter)- the function might attempt to erase elements that are out of range (i.e. UB).
As suggested by David in the comments, you can solve the issue with iter = myMap.erase(iter) (or using a range without side effects).

iterators can't access problems properly

I am trying to access the element of a vector using the iterator. But I get strange outputs.
std::vector<int> ivec{ 7, 6 , 8, 9} ;
std::vector<int>::iterator beg = ivec.begin();
std::vector<int>::iterator last = ivec.end();
std::cout << *beg << *last << std::endl;
But, In the above case the program shows me error: debug assertion failed. Vector iterator not dereferencable. and this error is particularly for *last. If I just print *beg that seems to wrong fine. But can't dereference the last one.
Other problem I get with iterator is during increment.
std::vector<int>::iterator beg = ivec.begin();
cout << *(beg++) ; // in this case it prints me value of 7
cout << *(++beg) ; // in this case it print me the right value of second place i.e. is 6
cout << *(beg+=1) ; // in this case we also print the second value i.e. 6
end iterators are not iterators that you can de-reference. They point past the last element into the container. There's a good reason why this needs to be true; but long and short, the end iterator does not actually point to any element. If you want the last element, you need to decrement the end iterator.
For your first example, std::vector<T>::end points to the theoretical element after the actual last element, so dereferencing it does not make sense. It is primarily used for checking when you have got past the end of the vector in a loop.
For your second example, the results are as you would expect:
cout << *(beg++) ; //increments beg after dereferencing
cout << *(++beg) ; //increments beg before dereferencing
cout << *(beg+=1) ; //dereferences the result of adding one to beg
As it is stated in here,
Return iterator to end, Returns an iterator referring to the past-the-end element in the vector container.
The past-the-end element is the theoretical element that would follow the last element in the vector. It does not point to any element, and thus shall not be dereferenced.
Because the ranges used by functions of the standard library do not include the element pointed by their closing iterator, this function is often used in combination with vector::begin to specify a range including all the elements in the container.
If the container is empty, this function returns the same as vector::begin.

Difference between std::vector::front() and begin()

Help on vector says of front()
Returns a reference to the first element in the vector container.
Unlike member vector::begin, which returns an iterator to this same element, this > function returns a direct reference.
Help on vector says of begin()
Returns an iterator referring to the first element in the vector container.
Notice that unlike member vector::front, which returns a reference to the first element, > this function returns a random access iterator.
And this code outputs:
char arr[] = { 'A', 'B', 'C' };
vector<char> vec(arr, arr+sizeof(arr));
cout << "address of vec.front() " << (void*)&vec.front() << endl;
cout << "address of vec.begin() " << (void*)&vec.begin() << endl;
address of vec.front() 00401F90
address of vec.begin() 0030F494
I don't understand what 'direct reference' means? In the case of begin() isn't a random access iterator just a pointer?
Can someone please point out the difference?
According to Stroustrup in The C++ Programming Language, Section 16.3.3; think of front() as the first element and begin() as a pointer to the first element.
In the case of begin() isn't a random access iterator just a pointer?
No, an iterator has some pointer semantics, but it's actually a class.
And even if it was, that should answer the question. It's like asking why the address of a pointer isn't the same as the address of the object it points to.
You'd get the same value if you dereference the iterator, which will give you the first element:
&(*vec.begin())
because
*vec.begin() == vec.front()
For a vector, begin() and end() return random access iterators. They might return a plain pointer; that's okay, because it meets the requirements to be a random access iterator. In particular, you can write *begin() to get a reference to the first object in the sequence (assuming there is one). front() gives you a reference to the first object in the sequence, without going through the intermediate iterator. Like this:
vector<int> v;
v.push_back(3);
int i = *v.begin(); // i == 3
int j = v.front(); // j == 3
Assuming you have at least 1 element in the vector,
vec.front()
is the same as
*vec.begin()
To keep it clear in your mind, always try to remember the following two lines assuming that you have a vector from STL called v:
v.front() = * v.begin()
&&
v.back() = * v.end()
that means if you have a vector:
v = {1,2,3,4};
and you have an iterator called IT, and you want to access the first and the last element
you can either do:
IT = v.begin();
std::cout<<*IT<<std::endl; // output : 1
IT = v.end();
std::cout<<*IT<<std::endl; // output : 4
or you can easily do this:
std::cout<<v.front<<std::endl; // output : 1
std::cout<<v.back<<std::endl; // output : 4
both will print the same output, the difference is just between if you want to use an iterator or not.

C++ Iterator randomly gets invalidated

I'm lost: An iterator of a vector of std::string works perfectly unless there is a function call (Z_UB->set() ) before it++. Here's the code:
std::vector< std::string >::iterator it = g_SPP.scenarios->getVector().begin();
std::cout << "begin of vector: " << *it << std::endl;
Z_UB->set("s1", "scn2", 350);
it++;
std::cout << "second of vector: " << *it << std::endl;
creates the following output
begin of vector: scn1
However, if I move the function call like this:
std::vector< std::string >::iterator it = g_SPP.scenarios->getVector().begin();
std::cout << "begin of vector: " << *it << std::endl;
it++;
std::cout << "second of vector: " << *it << std::endl;
Z_UB->set("s1", "scn2", 350);
The result is the following, which is the expected behaviour:
begin of vector: scn1
second of vector: scn2
Inside the Z_UB->set() function there is nothing left but the call itself:
void Parameter::set( std::string _i, std::string _j, float value) {
//int i = indexSets[0]->backIndex(_i);
//int j = indexSets[1]->backIndex(_j);
//data2D[0][0] = value;
}
So if I call the Z_UB->set() function after I created the iterator, accessing it will crash the program. Is there anything vital that I missed about Iterators?
Several possibilities:
Either you do not have a good reproductible example: maybe in your first run you had only one element in your vector (how is it filled?), and invoked undefined behaviour because you did not check it against g_SPP.scenarios->getVector().end()
Or Z_UB->set does not do what you think. Is it a polymorphic class? Is set virtual? Is the -> operator overloaded?
Is your app multithreaded and another thread is mutating your container?
If g_SPP is a global variable then iterators over it will be invalidated by any mutating operation.
Update -- this is from the 1998 ISO/ANSI spec:
The following invalidate all references, iterators, and pointers referring to elements of the sequence if an allocation is required. An allocation is required if the current capacity() is less than the target vector size.
void reserve(size_type n)
iterator insert(iterator position, const T& x),
void insert(iterator position, size_type n, const T& x),
void insert(iterator position, InputIterator first, InputIterator last), and
Erasure invalidates all references, iterators, and pointers referring to elements after the position of the initial erased element.
iterator erase(iterator position)
iterator erase(iterator first, iterator second)
Resizing a vector is equivalent to calling either insert or erase. According to 23.2.4.2/6: resize(sz, c=value_type()) has the same effect as:
if (sz > size())
insert(end(), sz - size(), c);
else if (sz < size())
erase(begin() + sz, end());
else
;
a std::vector<T>::iterator will be invalidated if you add or remove elements while iterating over it, if the vector needs to resize itself internally, when an element is added.
.getVector() returned a copy of the vector. Comparing an iterator to the end point of the iterator of a completely different object doesn't make sense. Returning a reference solved the problem.
#Xeo also pointed out a much better explanation: When creating an iterator from a copy like this:
std::vector< std::string >::iterator it = g_SPP.scenarios->getVector().begin();
the copy immediately is destroyed thus invalidating the just created iterator. So the iterator shouldn't have returned the first element in the first place, but I can merely guess that this is hidden deeply in the implementation of the compiler.