copying single character using std::copy - c++

I am trying use std::copy to copy from two different iterator. But during course of execution these two iterators can be pointing to same location. Why in this situation they do not copy the single characters.
std::string str1 = "ABC";
std::string::iterator itr1 = str1.begin();
std::string::iterator itr2 = str1.begin();
std::string result;
std::copy(itr1,itr2,result.begin());

The right bound of the range in STL is not inclusive. If you give it the same iterator twice, the result is an empty range. You want this:
std::copy(itr1,itr2+1,result.begin());
But then, beware that you are writing to a location with no reserved memory, which is Undefined behavior. You must use a back_insert_iterator
std::copy(itr1,itr2 + 1, std::back_inserter(result));

Write :
result.resize(1); //it must have some size
std::copy(itr1,itr2 + 1,result.begin());
Or better yet.
//no need to resize now!
std::copy(itr1,itr2 + N, std::back_inserter(result));
where N is number of characters you want to copy to result.

In your situation, you could simply do:
std::string result(itr1, itr1 + 1);
Since std::string has a constructor that takes two iterators to copy its content from.
Now for the explanations:
std::copy(itr1, itr2, res) copies all the elements starting at itr1 and stopping just before itr2 a the location specified by res.
That is, if itr1 == itr2 there is no "gap" between the two iterators and nothing is copied.
That's why the end() iterator usually points past the last element of a collection.
Consider the following vector, vec, which has 3 elements:
1, 2, 3, X
^ ^
| |
| \-- end() (X indicates a slot past the last element)
\----------- begin()
That is, if you use std::copy() with begin() and end() you will actually copy all the elements of vec.

The second parameter to copy() is the element after the last one copied; str1.end() would point after the last character, not before it. Your call is asking for 0 character to be copied, and that's what you're getting. You could advance itr2 by one before making the call.

Related

How to erase reverse_iterator correctly when erase and push_back happens?

I have a list container, which looks like:
std::list<int> l = {1,2,3,4,5,6,7,8};
i often erase elements, so i choose std::list.
but, i also want to find the elemnt in O(1), so i record the reverse_iterator.
For Example:
l.push_back(9);
auto s = l.rbegin(); // record the iterator of 9, in order to erase it in the future fastly.
cout << *s << endl;
l.push_back(10);
auto s2 = l.rbegin();
but when i erase like this:
l.erase(std::next(s).base()); // s the iterator of 9, in my brain
i want to erase 9, but actually, it erase 10.
I have two questions:
why i should use next? actually my *s can get the element, which is different with .end().
how can i make the erase happen in my previous saved iterator?
Since the iterator of the list is a bidirectional iterator, instead of using reverse_iterator, you can just use --l.end() to get the last valued iterator.
std::list<int> l = {1,2,3,4,5,6,7,8};
l.push_back(9);
auto s = --l.end(); // record the iterator of 9
l.push_back(10);
l.erase(s); // erase the iterator of 9
Demo.
l.rbegin().base() == l.end(), which is not the position of the last element, but the end of the list. and push_back again won't affect this existing iterator, it is still pointing to the end of the list.
Then std::next(l.rbegin()).base() == l.end() - 1, which now is pointing to the last element 10.
So if you want to remember the position of the 9, you better use a normal iterator instead of a reverse one, or, use a reverse iteractor whose base pointing to 9, and that should be auto s = std::next(l.rbegin()), and erase it as l.erase(s.base()).
the rule is &*r == &*(i-1)

remove algorithm unexpected behaviour [duplicate]

I am bit confused about the difference between the usage of std::remove algorithm. Specifically I am not able to understand what is being removed when I use this algorithm. I wrote a small test code like this:
std::vector<int> a;
a.push_back(1);
a.push_back(2);
std::remove(a.begin(), a.end(), 1);
int s = a.size();
std::vector<int>::iterator iter = a.begin();
std::vector<int>::iterator endIter = a.end();
std::cout<<"Using iter...\n";
for(; iter != endIter; ++iter)
{
std::cout<<*iter<<"\n";
}
std::cout<<"Using size...\n";
for(int i = 0; i < a.size(); ++i)
{
std::cout<<a[i]<<"\n";
}
The output was 2,2 in both the cases.
However, if I use erase with the remove something like this:
a.erase(std::remove(a.begin(), a.end(), 1), a.end());
I get the output as 2.
So my questions are:
(1). Is there any use of std::remove other than using it with erase function.
(2). Even after doing std::remove, why a.size() returns 2 and not 1?
I read the item in Scott Meyer's Effective STL book about the erase-remove idiom. But am still having this confusion.
remove() doesn't actually delete elements from the container -- it only shunts non-deleted elements forwards on top of deleted elements. The key is to realise that remove() is designed to work on not just a container but on any arbitrary forward iterator pair: that means it can't actually delete the elements, because an arbitrary iterator pair doesn't necessarily have the ability to delete elements.
For example, pointers to the beginning and end of a regular C array are forward iterators and as such can be used with remove():
int foo[100];
...
remove(foo, foo + 100, 42); // Remove all elements equal to 42
Here it's obvious that remove() cannot resize the array!
What does std::remove do?
Here's pseudo code of std::remove. Take few seconds to see what it's doing and then read the explanation.
Iter remove(Iter start, Iter end, T val) {
Iter destination = start;
//loop through entire list
while(start != end) {
//skip element(s) to be removed
if (*start == val) {
start++;
}
else //retain rest of the elements
*destination++ = *start++;
}
//return the new end of the list
return destination;
}
Notice that remove simply moved up the elements in the sequence, overwriting the values that you wanted to remove. So the values you wanted to remove are indeed gone, but then what's the problem? Let say you had vector with values {1, 2, 3, 4, 5}. After you call remove for val = 3, the vector now has {1, 2, 4, 5, 5}. That is, 4 and 5 got moved up so that 3 is gone from the vector but the size of vector hasn't changed. Also, the end of the vector now contains additional left over copy of 5.
What does vector::erase do?
std::erase takes start and end of the range you want to get rid off. It does not take the value you want to remove, only start and end of the range. Here's pseudo code for how it works:
erase(Iter first, Iter last)
{
//copy remaining elements from last
while (last != end())
*first++ = *last++;
//truncate vector
resize(first - begin());
}
So the erase operation actually changes the size of container and frees up the memory.
The remove-erase idiom
The combination of std::remove and std::erase allows you to remove matching elements from the container so that container would actually get truncated if elements were removed. Here's how to do it:
//first do the remove
auto removed = std::remove(vec.begin(), vec.end(), val);
//now truncate the vector
vec.erase(removed, vec.end());
This is known as the remove-erase idiom. Why is it designed like this? The insight is that the operation of finding elements is more generic and independent of underlying container (only dependent on iterators). However operation of erase depends on how container is storing memory (for example, you might have linked list instead of dynamic array). So STL expects containers to do its own erase while providing generic "remove" operation so all containers don't have to implement that code. In my view, the name is very misleading and std::remove should have been called std::find_move.
Note: Above code is strictly pseudocode. The actual STL implementation is more smarter, for example, using std::move instead of copy.
std::remove does not remove the actual objects, rather, pushes them to the end of the container. Actual deletion and deallocation of memory is done via erase. So:
(1). Is there any use of std::remove other than using it with erase function.
Yes, it helps to get a pair of iterators to a new sequence without having worry about proper de-allocation etc.
(2). Even after doing std::remove, why a.size() returns 2 and not 1?
The container still holds to those objects, you only have a new set of iterators to work with. Hence the size is still what it used to be.
i faced the same issue, trying to understand the difference.
the explanations that have been give so far are right on the money, but i only understood them after seeing an example;
#include <algorithm>
#include <string>
#include <iostream>
#include <cctype>
int main()
{
std::string str1 = "Text with some spaces";
std::string::iterator it = remove(str1.begin(), str1.end(), 't');
std::cout << str1 << std::endl;// prints "Tex wih some spaceses"
for (str1.begin();it != str1.end(); ++it)
{
std::cout << *it; //prints "es"
}
}
as you can see, the remove, only moves the lower case 't' to the end of the string, while returning a new iterator to the end of the new string (new string is the old string up to where the removed element are inserted)
this is why when you print the iterator that you got from "remove"
"Text with some spaces"
^ ^removes both 't', then shift all elements forward -1 //what we want to remove
"Text with some spaces"
^ end of string -2 //original state of string
"Tex with some spacess"
^end of string -3 //first 't' removed
"Tex wih some spaceses"
^end of string -4 //second 't' removed
"Tex wih some spaceses"
^new iterator that remove() returned -5 // the state of string after "remove" and without "erase"
if you pass the iterator you obtained from step 5 to "erase()" it will know to erase from there to the end of string re-sizing the string in process
To remove element with some condition(equal some value or other condition like less than) in container like vector, it always combine function member function erase and std::remove or std::remove_if.
In vector, the function erase can just delete element by position, like:
iterator erase (iterator position);
iterator erase (iterator first, iterator last);
But if you want to erase elements with some condition, you can combine it with std::remove or std::remove_if.
For example, you want to erase all the elements 6 in the below vector:
std::vector<int> vec{6, 8, 10, 3, 4, 5, 6, 6, 6, 7, 8};
// std::remove move elements and return iterator for vector erase funtion
auto last = std::remove(vec.begin(), vec.end(), 6);
for(int a:vec)
cout<<a<<" ";
cout<<endl;
// 8 10 3 4 5 7 8 6 6 7 8
vec.erase(last, vec.end());
for(int a:vec)
cout<<a<<" ";
cout<<endl;
// 8 10 3 4 5 7 8
std::remove works as below, it does't erase any elements, it just move elements and returns the iterator.
Possible implementation:
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);
return first;
}
Conclusion:
If you want to remove elements with some condition, you use vector::iterator erase (iterator first, iterator last); essentially.
First get range start:
auto last = std::remove(vec.begin(), vec.end(), equal_condition_value);
erase by range(always with end())
vec.erase(last, vec.end());
cited:
https://en.cppreference.com/w/cpp/algorithm/remove
Simplest I can come up with:
erase() is something you can do to an element in a container. Given an iterator/index into a container, erase( it ) removes the thing the iterator refers to from the container.
remove() is something you can do to a range, it re-arranges that range but doesn't
erase anything from the range.
remove doesn't "really" remove
anything, because it can't.
In order to "actually" remove the elements from container you need to access container APIs. Where as remove works only with iterators irrespective of what containers those iterators points to. Hence, even if remove wants an "actual remove", it can't.
Remove overwrite "removed" elements by the following elements that were not removed and then it is up to the caller to decide to use the returned new logical end instead of the original end.
In your case remove logically removed 1 from vector a but size remained to 2 itself. Erase actually deleted the elements from vector. [ from vector new end to old end ]
The main idea of remove is it cannot change the number of elements and it just remove elements from a range as per criteria.

Can I remove elements in the std::string object while iterating over it

Can I remove elements in the std::string object while iterating over it?
for (auto itr = str.rbegin(), rend = str.rend(); itr != str.rend() && *itr == '0'; ++itr)
{
str.pop_back();
}
No, that's not allowed. Modifying the contents of the string invalidates any iterators, particularly itr.
To remove trailing characters from a string, consider using find_last_not_of:
auto ix = str.find_last_not_of('0');
str.resize(ix + 1);
Another option is to use the erase function, which will return the next iterator in the sequence, thereby avoiding having any invalid iterators.
for (auto itr = str.rbegin(); itr != str.rend() && *itr == '0'; /*nothing*/)
itr = str.erase(itr);
That will erase the last character (as pop_back would) and safely advance the iterator, so you never actually have an invalid iterator anymore. The caveat is that you cannot you the rend iterator that you were calculating before, because it would be invalid; however, you weren't actually using it anyway.
You can remove elements as you iterate over the string, but you need to write your loop slightly differently to do it safely. In this case, we only really care about the last character in the string, so we can do something like this:
for (auto itr = str.rbegin();
itr != str.rend() && *itr == '0';
itr=str.rbegin())
{
str.pop_back();
}
Even though itr may be invalidated when we do pop_back on the string, we're re-fetching the value of str.rbegin() every iteration, and that's guaranteed to give a valid reverse iterator every time we call it. What we have left no longer really makes good use of a for loop though--we might about as well use a while loop:
while (str.rbegin() != str.rend() && *str.rbegin() == '0')
str.pop_back();
I think I'd rather write it something like:
while (!str.empty() && *str.rbegin() == '0')
str.pop_back();
...or (using a slightly cleaner equivalent of *str.rbegin():
while (!str.empty() && str.back() == '0')
str.pop_back();
According to reference of string::pop_back http://www.cplusplus.com/reference/string/string/pop_back/
Any iterators, pointers and references related to this object may be
invalidated.
So I guess you cannot do this in a for loop with iterators.
You do this:
while ( str.size() > 0 && str[ str.size()-1] == '0' ] )
str.pop_back();
Or you can carry out your for loop using counters instead of iterators.
According to the Scripture, Chapter 21.4.1, verse 6:
6 References, pointers, and iterators referring to the elements of a
basic_string sequence may be invalidated by the following uses of that
basic_string object:
— as an argument to any standard library function
taking a reference to non-const basic_string as an argument.
— Calling non-const member functions, except operator[], at, front, back, begin,
rbegin, end, and rend.
So I would say "no, not using pop_back".
But you can of course use the erase overload that returns an iterator and use that iterator instead of the one you erased, as for other containers.
According to the standard any use of s.erase() on a std::basic_string invalidates all pointers, references, and iterators to s. The relevant section in the standard is 21.4.1 [string.require] paragraph 6:
References, pointers, and iterators referring to the elements of a basic_string sequence may be invalidated by the following uses of that basic_string object:
as an argument to anys tandard library function taking a reference to non-const basic_string as`an argument.
Calling non-const member functions, except operator[], at, front, back, begin, rbegin, end, and rend.
The alterantive is to use the result or the erase() to get back a valid iterator to the current position. Alternatively, you might want to use erase() in combination with std::remove_if() to first reshuffle the string efficiently and then remove the actual content.

Why does a push_back on an std::list change a reverse iterator initialized with rbegin?

According to some STL documentation I found, inserting or deleting elements in an std::list does not invalidate iterators. This means that it is allowed to loop over a list (from begin() to end()), and then add elements using push_front.
E.g., in the following code, I initialize a list with elements a, b and c, then loop over it and perform a push_front of the elements. The result should be cbaabc, which is exactly what I get:
std::list<std::string> testList;
testList.push_back("a");
testList.push_back("b");
testList.push_back("c");
for (std::list<std::string>::iterator itList = testList.begin(); itList != testList.end(); ++itList)
testList.push_front(*itList);
for (std::list<std::string>::const_iterator itList = testList.begin(); itList != testList.end(); ++itList)
std::cout << *itList << std::endl;
When I use reverse iterators (loop from rbegin() to rend()) and use push_back, I would expect similar behavior, i.e. a result of abccba. However, I get a different result:
std::list<std::string> testList;
testList.push_back("a");
testList.push_back("b");
testList.push_back("c");
for (std::list<std::string>::reverse_iterator itList = testList.rbegin(); itList != testList.rend(); ++itList)
testList.push_back(*itList);
for (std::list<std::string>::const_iterator itList = testList.begin(); itList != testList.end(); ++itList)
std::cout << *itList << std::endl;
The result is not abccba, but abcccba. That's right there is one additional c added.
It looks like the first push_back also changes the value of the iterator that was initialized with rbegin(). After the push_back it does not point anymore to the 3rd element in the list (which was previously the last one), but to the 4th element (which is now the last one).
I tested this with both Visual Studio 2010 and with GCC and both return the same result.
Is this an error? Or some strange behavior of reverse iterators that I'm not aware of?
The standard says that iterators and references remain valid during an insert. It doesn't say anything about reverse iterators. :-)
The reverse_iterator returned by rbegin() internally holds the value of end(). After a push_back() this value will obviously not be the same as it was before. I don't think the standard says what it should be. Obvious alternatives include the previous last element of the list, or that it stays at the end if that is a fixed value (like a sentinel node).
Technical details: The value returned by rend() cannot point before begin(), because that is not valid. So it was decided that rend() should contain the value of begin() and all other reverse iterators be shifted one position further. The operator* compensates for this and accesses the correct element anyway.
First paragraph of 24.5.1 Reverse iterators says:
Class template reverse_iterator is an iterator adaptor that iterates from the end of the sequence defined
by its underlying iterator to the beginning of that sequence. The fundamental relation between a reverse
iterator and its corresponding iterator i is established by the identity:
&*(reverse_iterator(i)) == &*(i - 1).
I think to understand this, it's best to start by re-casting the for loop as a while loop:
typedef std::list<std::string> container;
container testList;
testList.push_back("a");
testList.push_back("b");
testList.push_back("c");
container::reverse_iterator itList = testList.rbegin();
while (itList != testList.rend()) {
testList.push_back(*itList);
++itList;
}
Along with that, we have to understand how a reverse_iterator works in general. Specifically a reverse_iterator really points to the element after the one you get when you dereference it. end() yields an iterator to just after the end of the container -- but for things like arrays, there's no defined way to point to just before the beginning of a container. What C++ does instead is have the iterator start from just after the end, and progress to the beginning, but when you dereference it, you get the element just before where it actually points.
That means your code actually works like this:
After that, you get pretty much what you expect, pushing back B and then A, so you end up with ABCCCBA.
Try using an iterator for both. Try:
std::list<std::string>::iterator i = testList.end();
and reverse through with --i

Iterator from both ends of a Vector

I have a vector of IntRect: vector.
How can I iterate from both ends of the list and stop the iterator when the iterator intersects?
vector<IntRect>::iterator itr = myVector.begin();
vector<IntRect>::reverse_iterator revItr.rbegin();
for (; /*check itr and revItr does not intersect, and itr and revItr do not end */ ; ++itr, ++revItr) {
IntRect r1 = *itr;
IntRect r2 = *revItr;
// do something with r1 and r2
}
Thank you.
if(!myVector.empty()) {
for(vector<IntRect>::iterator forwards = myVector.begin(),
backwards = myVector.end()-1;
forwards < backwards;
++forwards, --backwards) {
// do stuff
}
}
I think you need to check empty() with that implementation - suspect that end()-1 isn't defined if the vector is empty. I haven't used it before, but Dinkumware STL at least has operator < defined for vector iterators and it appears to do something sensible.
Also note that you need to check <, not just equality - that takes care of the (common) case where your vector has an even number of entries and the two iterators would step past one another.
You can use base function on the reverse iterator and compare the result with your forward iterator.
Remember that if you're moving both iterators, they will never be equal if the sequence has odd number of elements. You have to check the equality twice in each iteration.
None of the answers that I've seen account for the two iterators "passing in the night."
vector<IntRect>::iterator forward = myVector.begin(), backward = myVector.end();
while (forward != backward)
{
++forward;
// at this point they could be equal
if (forward == backward)
break;
--backward;
}
Your iterators point to the same thing if &(*itr) == &(*revItr)
Assuming nobody has done something stupid and overloaded operator& on IntRect.
I would replace the second (reverse) iterator with a regular one and have that initialised to --myVector.end(). Instead of incrementing it, decrement it and compare the iterator values.