erase map element using an iterator inside a function - c++

I need to erase map elements using an iterator inside a function which takes map iterator as argument, but getting runtime error(free(): double free detected). This is my code:
#include <iostream>
#include <map>
std::map<int32_t, int32_t> mapp;
void erasee(std::map<int32_t, int32_t>::iterator itr) {
itr = mapp.erase(itr);
}
int main()
{
mapp.emplace(1, 1000);
std::map<int32_t, int32_t>::iterator itr = mapp.begin();
while(itr != mapp.end()) {
std::cout << "before" << std::endl;
erasee(itr);
std::cout << "after" << std::endl;
}
return 0;
}

itr is passed to erasee by value. Consequently reassigning it has no effect after erasee returns.
As a quick fix you can pass it by reference:
void erasee(std::map<int32_t, int32_t>::iterator & itr) {
Though returning a new iterator might be a more readable solution.

Related

keeping an iterator valid while splicing a list C++

There are a few posts around iterators with lists here using the insert and splice here functions but I am still not able to translate them for my case, I am iterating across a list and if a condition is meet I want to splice (move) the element to another list, but as stated here the iterator jumps to the splices container. How can I keep the iterator related to the original loop as in the example below.
#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
#include <map>
#include <ctime>
#include <list>
using namespace std;
class Individual {
public:
Individual(bool state) : state_(state) {}
bool my_state(void) {
return state_;
}
private:
bool state_ = true;
};
int main () {
cout << "----------Enter Main----------" << endl;
list<Individual> list_individuals;
list<Individual> cache_list_individuals;
// initialise
for (auto i = 0; i < 100; ++i) {
if (i <= 50)
list_individuals.push_back(new Individual(true));
else
list_individuals.push_back(new Individual(false));
}
unsigned counter = 0;
for (auto iter = list_individuals.begin(); iter != list_individuals.end(); ++iter, ++counter) {
if ((*iter).my_state()) {
cache_list_individuals.splice(cache_list_individuals.begin(),list_individuals, iter);
// I need to make the iterator related to list_individuals not cache_list_individuals
}
}
cout << "----------Exit Main----------" << endl;
system("PAUSE");
return 0;
}
for (iter = list.begin(); iter != list.end();) {
otherIter = iter++;
if (condition) {
otherList.splice(otherList.cend(), otherIter, list);
}
}
Move incrementing the iterator into the loop.
Using a post increment, moves iter, and keeps it iterating through list, while otherIter is iterating through otherList after the splice().
You could use a copy of your loop iterator to do the splicing:
if ((*iter).my_state()) {
auto splice_iter = iter;
cache_list_individuals.splice(cache_list_individuals.begin(), list_individuals, splice_iter);
}
But after copy both iterators will point to the moved element in the cache_list_individuals list.
David C. Rankin's comment above is where my code was trying to go.

Validate the return value of copy_if

I would like to check if the return value of std::copy_if is valid.
Something like this
auto it=std::copy_if(s.begin(),s.end(),d.begin(),[&](...){...});
if([it]) // ????
{
// do something
}
The return value of copy_if marks the "one past the end" of the destination range. If you passed a range to copy_if that can hold all of your to-be-copied values then you can dereference everything between the begin of your output range up to it - 1.
#include <vector>
#include <algorithm>
#include <iostream>
int main()
{
std::vector<int> s{1,2,3,4,5,6,7,8,9,10};
std::vector<int> d(10);
auto ce = std::copy_if(s.begin(),s.end(),d.begin(),[&](int x){ return x > 5; });
for(auto i = d.begin(); i != ce; ++i)
{
std::cout << *i << "\n";
}
}
A variant of #Pixelchemist's answer is to erase from the returned iterator to the end of the destination. This leaves behind only those elements that satisfied the condition.
#include <vector>
#include <algorithm>
#include <iostream>
int main()
{
std::vector<int> s{1,2,3,4,5,6,7,8,9,10};
std::vector<int> d(10);
auto it = std::copy_if(s.begin(),s.end(),d.begin(),[&](int x){ return x > 5; });
d.erase(it, d.end());
for(int i : d)
{
std::cout << i << "\n";
}
}
copy_if returns a pointer one past the element it last copied. So in your case the destination range would be [d.begin(), it).
Not sure what type of error checking you would want to do but you can for example use the pointers to see how many elements were copied:
unsigned int elementsCopied = it - d.begin();
You can also iterate over the elements copied:
for(auto i = d.begin(); i != it; ++i)
{
//perform action on i
}
If you are still unsure about how copy_if works, c++ reference gives a clear explanation in my opinion.
Perhaps also interesting, this is a possible implementation of copy_if so you can see what is going on:
template <class InputIterator, class OutputIterator, class UnaryPredicate>
OutputIterator copy_if (InputIterator first, InputIterator last,
OutputIterator result, UnaryPredicate pred)
{
while (first!=last) {
if (pred(*first)) {
*result = *first;
++result;
}
++first;
}
return result;
}

How do I use two consecutive elements of a deque at once in a for loop?

I have to process element from a deque (first to last), but at each iteraton I need to use one element and the next too. So I'm trying to write a for loop that starts with mydeque.begin() and finishes at mydeque[mydeque.size()-1]. Also; I would like to know if my iterator deque::iterator it has a next method (it->next()), to make operations like *it - *it->next(). Thank you very much.
Here's how:
#include <deque>
#include <iostream>
int main() {
std::deque<int> test = {1,2,3,4,5,6,7,8};
for(auto i = test.begin(); i != test.end(); i++) {
auto next = std::next(i);
std::cout << *i << *next << std::endl;
if(next==test.end())
{
//Do something. This is the last element.
break;
}
}
}
EDIT: Watch out for deques with only one element. Do this by performing a check such as if(test.begin()==test.end()).
EDIT: My initial solution was indeed a bit error prone and unprecise.
This can easily be done using iterators, see this little example:
#include <deque>
#include <iostream>
int main() {
std::deque<int> test = {1,2,3,4,5,6,7};
for(auto i = test.begin(); i != test.end(); ++i) {
auto next = std::next(i);
if(next != test.end()) {
std::cout << *i << " " << *next << std::endl;
}
}
}
You can simply increment the iterator by 2 and use std::next to also pick the following item (since the offset of std::next defaults to 1).

How can I make a pointer to list iterator to pass into function as an argument?

I have this function names_list() to display the list and I want to pass the reference to my string list iterator to this function and print the whole list.
#include <iostream>
#include <list>
using namespace std;
void names_list(list<string>::iterator *i,list<string> *n){
while(*i != *(n.end()))
{
cout<<i<<endl;
i++;
}
}
int main(){
list<string> names;
list<string> *name_ptr = names;
names.push_back("vivek");
names.push_back("Anup");
names.push_back("kali");
list<string>:: iterator iter = names.begin();
names_list(&iter,&name_ptr);
return 0;
}
How can I do it?
The best way of implementing your function is to pass 2 iterators by value (this is how many algorithms in the C++ Standard Library work): an iterator to the beginning of the list, and one to the end:
void names_list(list<string>::iterator beg, list<string>::iterator end){
while( beg != end)
{
cout << *beg++ << endl; // we increment here
}
}
then invoke your function simply as
names_list(names.begin(), names.end());
In this way you separate your algorithm from the data structure. Even better, you can pass arbitrary iterators via templates, and your function will work then with arbitrary containers:
template<typename T>
void names_list(typename T::iterator beg, typename T::iterator end)
{
while( beg != end)
{
cout << *beg++ << endl; // we increment here
}
}
for (std::set<std::string>::const_iterator it = NameList.begin(); it != NameList.end(); ++it)
std::cout << *it << std::endl;
The iterator dereference (*it) will give you the string containing the name.
In your method you should pass a reference to the list of name and print each of them using the code I have provided.
EDIT The final code would look like this:
void names_list(list<string>& n){
for (list<string>::const_iterator it = n.begin(); it != n.end(); ++it)
std::cout << *it << std::endl;
}
int main()
{
list<string> names;
names.push_back("vivek");
names.push_back("Anup");
names.push_back("kali");
names_list(names);
system("pause"); // return 0
}
Make sure you include the following libraries: iostream, list, string

Why can I not convert a reverse iterator to a forward iterator?

Well, I know why, it's because there isn't a conversion, but why isn't there a conversion? Why can forward iterators be turned to reverse iterators but not the other way round? And more importantly, what can I do if I want to do this? Is there some adapter that allows you to iterate backwards using a forward iterator?
std::vector<int> buffer(10);
std::vector<int>::iterator forward = buffer.begin();
std::vector<int>::reverse_iterator backward = buffer.rbegin();
++forward;
++backward;
std::vector<int>::iterator forwardFromBackward = std::vector<int>::iterator(backward); // error! Can't convert from reverse_iterator to iterator!
std::vector<int>::reverse_iterator backwardFromForward = std::vector<int>::reverse_iterator(forward); // this is fine
You could write a helper function. One particularity of reverse_iterator is that base() gives a forward iterator that is next from the value that the reverse iterator dereferences to. This is because a reverse iterator physically points to the element after the one it logically points to. So to have the forward iterator to the same item as your reverse_iterator, you'll need to decrement the result of base() by one, or you could increment the reverse iterator first, then take the .base() of that.
Both examples are shown below:
#include <iostream>
#include <vector>
#include <iterator>
//result is undefined if passed container.rend()
template <class ReverseIterator>
typename ReverseIterator::iterator_type make_forward(ReverseIterator rit)
{
return --(rit.base()); // move result of .base() back by one.
// alternatively
// return (++rit).base() ;
// or
// return (rit+1).base().
}
int main()
{
std::vector<int> vec(1, 1);
std::vector<int>::reverse_iterator rit = vec.rbegin();
std::vector<int>::iterator fit = make_forward(rit);
std::cout << *fit << ' ' << *rit << '\n';
}
Warning: this behavior is different from that of the reverse_iterator(iterator) constructor.
It's very common to have two (reverse) iterators span a range of values (such as in begin(),end() and rbegin(),rend()). For any range described by the two reverse iterators rA,rB, the range rB.base(),rA.base() will span the same range in the forward direction.
#include <iostream>
#include <iterator>
#include <vector>
int main() {
std::vector<int> vec{10,11,12,13,14,15};
// spans the range from 13 to 10
auto rfirst=std::rbegin(vec)+2;
auto rlast=std::rend(vec);
// Loops forward, prints 10 11 12 13
for(auto it = rlast.base(); it != rfirst.base(); ++it){
std::cout << *it << " ";
}
}
If conceptually you are only interested in a single item (such as the result of find_if), then use make_forward by #visitor. Even in this case, the range idea helps to keep track of the validity of the reverse iterator:
#include <iostream>
#include <iterator>
#include <vector>
#include <algorithm>
int main() {
std::vector<int> vec{10,11,12,13,14,15};
auto rfirst=std::rbegin(vec);
auto rlast=std::rend(vec);
auto rfound = std::find_if(rfirst,rlast, [](int v){ return v<13; });
if(rfound != rlast){
std::cout << *rfound << " "; // prints 12
auto forwardFound = make_forward(rfound) ;
std::cout << *forwardFound << " "; // prints 12
}
}
You can get forward iterator from reverse iterator using this code
container.begin() + (reverseIter - container.rbegin() - 1);