std::map find distance with iterators, program does not terminate - c++

As I compile ( g++ -std=c++14 map.cpp ) and run this program, it doesn't seem to terminate. Can any one explain Why? However as I do find('a') instead of 'c' it gives a zero.
#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <algorithm>
using namespace std;
int main()
{
map<char, float> m;
m['a'] = 3.4;
m['b'] = 5.3;
m['c'] = 33.3;
m['d'] = 43.;
auto it = m.find( 'c' );
cout << "distance : " << std::distance( it , m.begin() ) << endl;
}

Use
std::distance( m.begin(), it )
Otherwise the call
std::distance( it , m.begin() )
has undefined behavior because there is used an invalid range. Ranges in C++ are specified like [first, last ) where first precedes or equal to last. In the last case when first is equal to last the range is empty.
From the C++ Standard (27.4.3 Iterator operations)
4 Effects: If InputIterator meets the requirements of random access
iterator, returns (last - first); otherwise, returns the number of
increments needed to get from first to last.

std::distance(first,last) starts running from first and advances the iterator until it reaches the last. In your case this will never happen because it is most likely found after m.begin() so it'll loop forever. change the order of parameters given to std::distance
std::distance reference:
The behavior is undefined if last is not reachable from first by
(possibly repeatedly) incrementing first.

Related

Why does std::distance() for std:list<int>::iterator not return a negative number when last is before first?

std::distance is giving me a circular distance on std::list, not a relative distance. Why?
#include <list>
#include <iostream>
#include <iterator>
using namespace std;
int main(){
list<int> derp = {1,2,3,4};
auto begin = derp.begin();
auto end = derp.end();
end--;
cout << distance(end, begin) << endl;
cout << distance(begin, end) << endl;
}
When I run this, the following output happens:
2
3
I expect the following:
-3
3
Why is this happening?
Your code has undefined behavior. For std::distance
If InputIt is not LegacyRandomAccessIterator, the behavior is undefined if last is not reachable from first by (possibly repeatedly) incrementing first. If InputIt is LegacyRandomAccessIterator, the behavior is undefined if last is not reachable from first and first is not reachable from last.
The iterator of std::list is not RandomAccessIterator, and its begin is not reachable from end by incrementing end.
For iterators that do not meet the requirements of a random access iterator, std::distance returns the number of times first (the first argument) must be incremented to equal last (the second argument).
You are using a std::list, which does not have random access iterators. In the case of distance(end, begin), no matter how many times you increment end, it will never equal begin. Thus, the behaviour is undefined, and the result depends on the particulars of your standard library implementation.

Iterator confusion using maps

sorry because this question isn't really advanced, but I am having lots of trouble understanding why this program works the way it does.
#include <iostream>
#include <fstream>
#include <set>
#include <vector>
#include <map>
using namespace std;
int main() {
ofstream fout("castle.out");
ifstream fin("castle.in");
map<int, int, greater<int> > cnt;
map<int, int, greater<int> >::iterator x;
x = cnt.begin();
cnt[1] = 0;
cnt[2] = 7;
fout << x->first; //This outputs 2
x++;
fout << x->second;//This outputs 2 again, why not 0?
return 0;
}
So I defined a map called cnt, and then made an iterator for it x. I ordered it by greatest integer to least greatest integer. I set that iterator equal to x.begin(), and then I outputted the value of x, using first. But then I wanted to output the value 0, so I did one x++; and then tried to output the value of x->first. The idea behind this was that the iterator would increase by one and point to the next pair in my map, so then it would point to 1, which comes after the 2.
Why does it not work and give me 2 again?
I realized that if I do this instead:
x++;
x++:
fout << x-> first;
with two x++, I will have the value 1. Why is this? Thanks!
Your code has undefined behavior.
x = cnt.begin();
Sets x to begin() while the container is empty which effectively gives you the end() iterator. Since std::map::operartor[] doesn't invalidate any iterators you still have an end() iterator and dereferencing it is undefined behavior.

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).

binary_search in c++ unexpected behaviour

The following snippet is returning me 0. I expected it to be 1. What's wrong going on here?
#include <iostream>
#include <iterator>
#include <ostream>
#include <algorithm>
#include <vector>
using namespace std;
int main(){
vector<int> v;
int arr[] = {10,20,30,40,50};
v.push_back(11);
v.push_back(22);
copy(arr,arr + sizeof(arr)/sizeof(arr[0]),back_inserter(v)); // back_inserter makes space starting from the end of vector v
for(auto i = v.begin(); i != v.end(); ++i){
cout << *i << endl;
}
cout << endl << "Binary Search - " << binary_search(v.begin(), v.end(), 10) <<endl; // returns bool
}
I am using gcc /usr/lib/gcc/i686-linux-gnu/4.6/lto-wrapper
I ran the program and saw this:
11
22
10
20
30
40
50
Binary Search - 0
Your array is not sorted, therefore, binary search fails. (it sees 11 in the first position, and concludes 10 does not exist here)
You either want to ensure the array is sorted before binary searching or use the regular std::find.
binary_search says:
Checks if the sorted range [first, last) contains an element equal to
value. The first version uses operator< to compare the elements, the
second version uses the given comparison function comp.
Your list is not sorted, it contains the elements 11 and 22 prior to 10.
Your array is not sorted, so binary_search got undefined behavior. Try std::find instead
bool found = std::find(v.begin(), v.end(), 10) != v.end()
ยง25.4.3.4 of the C++11 standard (3242 draft)
Requires: The elements e of [first,last) are partitioned with respect to the expressions e < value and !(value < e) or comp(e,
value) and !comp(value, e). Also, for all elements e of [first, last),
e < value implies !(value < e) or comp(e, value) implies !comp(value,
e).
"Unexpected behavior"? There's nothing unexpected here.
The whole idea of binary search algorithm is taking advantage of the fact that the input array is sorted. If the array is not sorted, there can't be any binary search on it.
When you use std::binary_search (as well as all other standard binary search-based algorithms), the input sequence must be sorted in accordance with the same comparison predicate as the one used by std::binary_search. Since you did not pass any custom predicate to std::binary_search, it will use the ordering defined by < operator. That means that your input Sequence of integers must be sorted in ascending order.
In your case the input sequence does not satisfy that requirement. std::binary_search cannot be used on it.

std::vector and std::min behavior

Why following program is not returning minimum value as 1.
#include <vector>
#include <algorithm>
#include <iostream>
int main ( int argc, char **argv) {
std::vector<int> test;
test.push_back(INT_MAX);
test.push_back(1);
int min = *(std::min(test.begin(), test.end()));
std::cout << "Minimum = " << min << std::endl;
}
It returns minimum values as 2147483647
You could try this:
int min = *std::min_element(test.begin(), test.end());
std::min
Return the lesser of two arguments
Returns the lesser of a and b. If both are equivalent, a is returned.
std::min_element
Returns an iterator pointing to the element with the smallest value in the range [first,last). The comparisons are performed using either operator< for the first version, or comp for the second; An element is the smallest if no other element compares less than it (it may compare equal, though).
Be aware that std::vector<T>::end() does NOT give you an iterator to the last element. It returns an iterator pointing BEHIND the last element.
If you want to address the first and last element with iterator logic you need to use (test.begin(), test.end()-1).