Is map::find safe? - c++

I'm trying to test if "find" is safe in std:map so I've erased an element after I use "find" to test it but the iterator to the element is still valid. Even if I use find again it finds the erased element again.
According to documentation:
Iterators, pointers and references referring to elements removed by the function are invalidated.
All other iterators, pointers and references keep their validity.
Why does the second iterator auto it_2 = numeros.find("uno"); finds the element if it was erased?
Why does std::cout << it->first << " : " << it->second << std::endl; after "erase" prints the element? It means find is safe when the element is removed from the map?
This is my example.
#include <iostream>
#include <map>
int main(int argc, char *argv[])
{
std::map<std::string,unsigned int> numeros = { {"uno",1}, {"dos",2}, {"tres",3}};
auto it = numeros.find("uno");
std::cout << it->first << " : " << it->second << std::endl;
std::cout << std::endl;
numeros.erase("uno");
std::cout << it->first << " : " << it->second << std::endl;
std::cout << std::endl;
auto it_2 = numeros.find("uno");
std::cout << it_2->first << " : " << it_2->second << std::endl;
std::cout << std::endl;
for (auto i=numeros.begin(); i!=numeros.end(); ++i)
std::cout << i->first << " : " << i->second << std::endl;
return 0;
}
Output
uno : 1
uno : 1
uno : 1
dos : 2
tres : 3
Thank you!

numeros.erase("uno"); invalidates the iterator it as per your quote. This means that you are not allowed to dereference the iterator anymore. Doing so anyway has undefined behavior.
Therefore your program has undefined behavior because you dereference the iterator in the next line
std::cout << it->first << " : " << it->second << std::endl;
Undefined behavior means your program could do anything. There are no guarantees that anything specific will happen anymore. There are no guarantees that you will get any error or warning either.
(Assuming you corrected the undefined behavior above:)
The second find in
auto it_2 = numeros.find("uno");
does not find the erased element. If .find does not find any element it returns the past-the-end iterator numeros.end(), which is what is happening here. Dereferencing the past-the-end iterator also has undefined behavior. So the following line
std::cout << it_2->first << " : " << it_2->second << std::endl;
which dereferences the past-the-end iterator also causes undefined behavior and your program to have no behavior guarantees.
You need to always check the result of find against end to verify that it found an element:
if(it_2 != numeros.end()) {
std::cout << it_2->first << " : " << it_2->second << std::endl;
} else {
std::cout << "uno not found!" << std::endl;
}

Related

how to print the contents of the vector to screen in c++ whose each element is pair in a pair

I am working on a assignment in which the elements of the vector of this type vector<pair<string,pair<int,int> > > A .
for(auto it=A.begin();it!=A.end();it++)
cout <<*it.first<<" "<< *it.second.first <<" "<<*it.second.second;
but it is showing errors.
Can anyone help me?
This is much, much simpler with modern C++ language features (C++17):
for (const auto &[s, p] : A)
{
const auto &[a, b] = p;
std::cout << s << " " << a << " " << b << std::endl;
}
If your C++ textbook and/or compiler doesn't cover C++17, it is really worth one's time to update your documentation and/or your compiler to the current C++ standard.
you need to use (*it).first instead of *it.first, because *it.first means a iterator which is it.first, but actually the iterator is (*it).
You can get rid of this problem by using ->, like it->first. Because if you use -> it is lot easier than using *.
vector<pair<string,pair<int,int> > > A;
for(auto it = A.begin(); it != A.end(); it++){
//cout << (*it).first << " " << (*it).second.first << " " << (*it).second.second;
cout << it->first << " " << it->second->first << " " << it->second->second;
}
You can use range-based loop instead of iterators to avoid the problems with *:
for(const auto& itr:A)
{
std::cout<< "Base Pair 1st: "<<itr.first<<" level pair 1st:"<<itr.second.first<<" level pair 2nd "<<itr.second.second;
}

How to actually "clear" a vector in C++?

How to clear content in a simple way?
If I use vec_vec.clear(); only, there is still something in the vector that has not been cleaned up.
#include <iostream>
#include <vector>
int main()
{
std::vector<std::vector<int>> vec_vec(10);
vec_vec[0].push_back(1);
vec_vec[0].push_back(2);
vec_vec[0].push_back(3);
vec_vec[0].push_back(4);
for (auto i : vec_vec[0])
std::cout << i << " ";
std::cout << "." << std::endl;
vec_vec.clear();
for (auto i : vec_vec[0])
std::cout << i << " ";
std::cout << "." << std::endl;
vec_vec[0].clear();
for (auto i : vec_vec[0])
std::cout << i << " ";
std::cout << "." << std::endl;
for (int i=0; i<vec_vec.size(); i++)
vec_vec.erase(vec_vec.begin() + i);
for (auto i : vec_vec[0])
std::cout << i << " ";
std::cout << "." << std::endl;
return 0;
}
1 2 3 4 *
0 0 3 4 *
*
*
vec_vec.clear();
for (auto i : vec_vec[0])
After this clear, vec_vec is empty, so the expression vec_vec[0] has undefined behavior.
Undefined behavior means anything at all might happen, and it's the fault of the program, not the fault of the C++ compiler, library, etc. So it might act like an empty vector, it might crash your program, it might print some values, or it might do what you expect today, then break at the worst possible time later on.
See also this Q&A on Undefined, unspecified, and implementation-defined behavior.

unordered_map pair of values c++

I am trying to use the unordered_map in C++, such that, for the key I have an int, while for the value there is a pair of floats. But, I am not sure how to access the pair of values. I am just trying to make sense of this data structure. I know to access the elements we need an iterator of the same type as this unordered map declaration. I tried using iterator->second.first and iterator->second.second. Is this the correct way to do access elements?
typedef std::pair<float, float> Wkij;
tr1::unordered_map<int, Wkij> sWeight;
tr1::unordered_map<int, Wkij>:: iterator it;
it->second.first // access the first element of the pair
it->second.second // access the second element of the pair
Thanks for your help and time.
Yes, this is correct, but don't use tr1, write std, since unordered_map is already part of STL.
Use iterators like you said
for(auto it = sWeight.begin(); it != sWeight.end(); ++it) {
std::cout << it->first << ": "
<< it->second.first << ", "
<< it->second.second << std::endl;
}
Also in C++11 you can use range-based for loop
for(auto& e : sWeight) {
std::cout << e.first << ": "
<< e.second.first << ", "
<< e.second.second << std::endl;
}
And if you need it you can work with std::pair like this
for(auto it = sWeight.begin(); it != sWeight.end(); ++it) {
auto& p = it->second;
std::cout << it->first << ": "
<< p.first << ", "
<< p.second << std::endl;
}

c++ vector iterator deference inconsistency

I have the following code. When dereference in line 5, I got wrong value of (*it)->sec. while in line 8, I can obtain correct value. The only difference I noticed is one is inside the for loop, the other is outside the for loop. Is there some subtle point I missing here. I basically want to obtain the member value of the first element in the vector. What's the correct way of obtaining the first (*it)->sec before(outside) the for loop?
void print_allAddresses(std::vector<EntryObj *> EntryObj_vec){
std::cout << "time(sec:microsec) dataType memoryValue" << std::endl;
std::vector<EntryObj *>::iterator it;
it = EntryObj_vec.begin();
std::cout << (*it)->sec << std::endl; //EntryObj_vec.front()->sec also wrong here.
for(it = EntryObj_vec.begin(); it != EntryObj_vec.end(); ++it){
if(!(*it)->parameters.empty()){
std::cout << (*it)->sec << "." << (*it)->microsecond << " ";
std::map<std::string, std::string>::iterator it_map;
for (it_map = (*it)->parameters.begin(); it_map != (*it)->parameters.end(); it_map++){
std::cout << "(" << it_map->first<< ")" << " " << it_map->second << std::endl;
}
}
}
return;
}

Why is the data pointed by the iterator kept, after deleting it from the list

In this sample program, why the value of the data pointed by the iterator is kept, even after the list is empty?
Is it something bound to happen due to the implementation of iterators in C++ (i.e. the value of the object is kept into the iterator) or is it because the segment of the memory was declared as free for used, but hasn't been changed yet?
#include <iostream>
#include <list>
using namespace std;
int main ()
{
list<int> mylist;
list<int>::iterator it = mylist.begin();
cout << "printing: " << *it << endl;
mylist.push_back(77);
mylist.push_back(22);
// now front equals 77, and back 22
mylist.front() -= mylist.back();
it = mylist.begin();
cout << "printing: " << *it << endl;
cout << "mylist.front() is now " << mylist.front() << '\n';
// trying to delete all elements and then see how the iterators are handling it
it = mylist.begin();
cout << "printing: " << *it << endl;
mylist.remove(55);
cout << "printing: " << *it << endl;
mylist.remove(22);
cout << "printing: " << *it << endl;
cout << "mylist size: " << mylist.size() << endl;
cout << "mylist.front() is now " << mylist.front() << '\n';
cout << "printing: " << *it << endl;
return 0;
}
And this is the output:
printing: 495034304
printing: 55
mylist.front() is now 55
printing: 55
printing: 55
printing: 55
mylist size: 0
mylist.front() is now 38375440
printing: 55
Is it something bound to happen due to the implementation of iterators in C++
No, it's undefined behaviour. The iterator has become invalid, and can't be used.
is it because the segment of the memory was declared as free for used, but hasn't been changed yet?
Yes, that's why you observed what you observed. But the memory could be reused for something else, or made inaccessible - you can't rely on any observations of undefined behaviour.
Iterator is invalidated by you operations, but it may still point to memory with the previous value. Anyway, accessing it after the value is removed from the list is undefined behaviour.
#include <stdio.h>
int main(int argc, char **argv)
{
int *p = NULL;
p = (int*)malloc(sizeof(int));
*p = 5;
printf("P: %d\n", *p);
free(p);
printf("P: %d\n", *p);
}
Why is this still a surprise? Marking a pointer as invalid has nothing to do with what is stored where it used to point.