C++ map::find & map::at performance difference - c++11

I was grading some exercises and at a specific program although the algorithm seemed correct it would be too slow (and I mean too slow). The program was accessing a map using map::at (introduced in C++11). With a minimum change of replacing at with find (and fixing the syntax) the same program would be really fast (compared to the original version).
Looking at cplusplus.com both methods claim to have the same complexity and I couldn't see why one would be different from the other (other than API reason, not throwing an exception, etc).
Then I saw that the description in the section about data races is different. But I don't fully understand the implications. Is my assumption that map::at is thread safe (whereas map::find is not) and thus incurring some runtime penalties correct?
http://www.cplusplus.com/reference/map/map/at/
http://www.cplusplus.com/reference/map/map/find/
Edit
Both are in a loop called 10.000.000 times. No optimization flags. Just g++ foo.cpp. Here is the diff (arrayX are vectors, m is a map)
< auto t = m.find(array1.at(i));
< auto t2 = t->second.find(array2.at(i));
< y = t->second.size();
< cout << array.at(i) << "[" << t2->second << " of " << y << "]" << endl;
---
> auto t = m.at(array1.at(i));
> x = t.at(array2.at(i));
> y = m.at(array1.at(i)).size();
> cout << array.at(i) << "[" << x << " of " << y << "]" << endl;

The performance difference you are observing can be attributed to object copying.
auto t = m.at(array1.at(i));
According to template argument deduction rules (same are applied for the auto specifier), in the above statement, t is deduced to mapped_type, which triggers an object copy.
You need to define t as auto& t for it to be deduced to mapped_type&.
Related conversation: `auto` specifier type deduction for references

Related

C++11 set range based for using structs as elements

Let's say I have a struct like this:
struct Something{
string name;
int code;
};
And a set of Something type:
set<Something> myset;
myset.insert({"aaa",123,});
myset.insert({"bbb",321});
myset.insert({"ccc",213});
What's wrong with this?
for (auto sth : myset){
cout << sth.name;
cout << sth.code;
}
Along the same lines... why can't I modify an element (even when the set contains plain int items) using something like this?
for (auto &sth : myset){
sth=[some value];
}
I know I can do this with vectors and maps. Why not sets?
Thanks!
Modifying an element of a set implies its position in the set's order can change. Because your compiler cannot know what exactly a particular set uses to determine its element's orders. Well, it could, theoretically, but even then it would be nearly impossible to keep track of the rearrangements while iterating through the container. It would make no sense.
What you can do, if you want to modify the elements of a set in such a way that you know will not change their order in a set, you can make the non-ordering members of your struct mutable. Note that if you make a mistake and the set's order is disturbed, any other operations on the set (like a binary search) will give incorrect results after that faulty modification. If you don't want to make members mutable, const_cast is an option, with the same caveats.
To elaborate on my answer above, an example:
#include <iostream>
#include <set>
struct bla
{
std::string name;
int index;
};
bool operator<(const bla& left, const bla& right) { return left.index < right.index; }
int main()
{
std::set<bla> example{{"har", 1}, {"diehar", 2}};
// perfectly fine
for(auto b : example)
std::cout << b.index << ' ' << b.name << '\n';
// perfectly fine - name doesn't influence set order
for(auto& b : example) // decltype(b) == const bla&
const_cast<std::string&>(b.name) = "something";
// better than first loop: no temporary copies
for(const auto& b : example)
std::cout << b.index << ' ' << b.name << '\n';
// using a "universal reference auto&&", mostly useful in template contexts
for(auto&& b : example) // decltype(b) == const bla&
std::cout << b.index << ' ' << b.name << '\n';
// destroying order of the set here:
for(auto& b : example)
const_cast<int&>(b.index) = -b.index;
// anything here relying on an ordered collection will fail
// This includes std::set::find, all the algorithms that depend on uniqueness and/or ordering
// This is pretty much all that will still work, although it may not even be guaranteed
for(auto&& b : example)
std::cout << b.index << ' ' << b.name << '\n';
}
Live code on Coliru.
Note the first const_cast is only ok because the underlying example isn't const in the first place.

SDL2 - how to get the appropriate display resolution

I'm trying to open a fullscreen window using SDL2. I've thoroughly looked at the documentation on Display and window management ( https://wiki.libsdl.org/CategoryVideo )... however I don't understand what the best practice would be to get the display resolution I am actually working on.
I have the following sample code:
SDL_DisplayMode mMode;
SDL_Rect mRect;
int ret0 = SDL_GetDisplayBounds(0, &mRect);
std::cout << "bounds w and h are: " << mRect.w << " x " << mRect.h << std::endl;
int ret2 = SDL_GetCurrentDisplayMode(0, &mMode);
std::cout << "current display res w and h are: " << mMode.w << " x " << mMode.h << std::endl;
int ret3 = SDL_GetDisplayMode(0, 0, &mMode);
std::cout << "display mode res w and h are: " << mMode.w << " x " << mMode.h << std::endl;
I am working on a single display that has a resolution of 1920x1080. However, the printed results are:
program output
It seems that SDL_GetDisplayMode() is the only function that displays the correct resolution, so I'd be inclined to use that one. However, I've read that when it comes to SDL_GetDisplayMode(), display modes are sorted according to a certain priority, so that calling it with a 0 returns the largest supported resolution for the display, which is not necessarily the actual resolution (see also: SDL desktop resolution detection in Linux ).
My question is: what is the best practice to obtain the correct resolution?

what's the difference between *iter.first and iter->first?

vector<int> a = { 1,2,3,4,5,6,7 };
pair<vector<int>, vector<int>::iterator> pair_of_itr; //not working showing wrong directional error!
auto pair_of_itr = minmax_element(a.begin(), a.end());
cout << *pair_of_itr.first << " " << *pair_of_itr.second << endl; // working with auto but not with the PAIR of iterator.
//cout << pair_of_itr->first << " " << pair_of_itr->second << endl // not working
return 0;
here i have explained via comments. plz do refer comments.
a->b is the same as (*a).b. *a.b is the same as *(a.b). So they differ in whether a is dereferenced, or a.b is dereferenced.
In your case, auto pair_of_itr = std::minmax_element ... creates a std::pair of iterators, and it is the iterator you want to dereference. So that would be *pair_of_itr.first. *pair_of_itr is ill-formed because a std::pair is not itself a pointer or iterator.
The problem with pair<vector<int>, vector<int>::iterator> pair_of_itr; is simply that the first element of the pair is a std::vector, not a std::vector::iterator. So in that case neither pair_of_itr nor pair_of_itr.first can be dereferenced. *pair_of_itr.second would compile, because the second element is an iterator.
It's usually a good idea to add redundant parentheses, particularly if you needed to ask whether they were necessary. Other people also might not remember that *a.b means *(a.b), and the parentheses don't cost a lot.

std::unordered_map iterator returns erased keys, why and how to skip them

I am very new to C++ programming and have stumbled across a behaviour that confuses me and makes my coding harder. I have searched for answer a bit and could not find anything - I have also scrolled through C++ reference pages and that did not help either (please don't crucify me if the answer is in there - the page isn't role model for explaining things). Maybe I am missing something really obvious.
Could someone explain, the following behaviour of std::unordered_map ?
std::unordered_map<std::string, std::string> test_map;
test_map["test_key_1"] = "test_value_1";
test_map["test_key_2"] = "test_value_2";
std::cout << "'test_key_1' value: " << test_map["test_key_1"] << std::endl; // This returns "test_value_1"
std::cout << "test_map size before erase: " << test_map.size() << std::endl; // This returns 2
test_map.erase("test_key_1");
std::cout << "test_map size after erase: " << test_map.size() << std::endl; // This returns 1
std::cout << "'test_key_1' value after erase: " << test_map["test_key_1"] << std::endl; // This returns empty string
std::cout << "'non_existing_key' value: " << test_map["non_existing_key"] << std::endl; // This returns empty string
test_map.rehash(test_map.size()); // I am doing this because vague hints from internet, code behaves
// same way without it.
for (std::unordered_map<std::string, std::string>::iterator it = test_map.begin();
it != test_map.end(); ++it)
{
std::cout << "Key: " << it->first << std::endl;
}
// Above loop return both 'test_key_1' and 'test_key_2'.
// WHY!?
Why iterator is returning items that were already erased ? How can I make iterator return only items that are present in map ?
I will be grateful for any help, as I am really lost.
You are using operator[] to access previously erased elements which
Returns a reference to the value that is mapped to a key equivalent to key, performing an insertion if such key does not already exist.
If you need just to search for given key, use find method that returns map.end() if element was not found.

Can someone explain me the output ? (C++11)

int main(){
auto func1 = [](int y) {
cout << y << " ";
};
auto func2 = [](int y) {
cout << y * y << " ";
};
cout << "func1 is : " << typeid(func1).name() << endl;
cout << "func2 is : " << typeid(func2).name() << endl;
cout << "main is : " << typeid(main).name() << endl;
}
OSX output:
func1 is : Z4mainE3$_0
func2 is : Z4mainE3$_1
main is : FivE
Can someone explain the output ??
Thanks, I am just exploring some c++11 features.
What you are seeing here is the name mangled name of each of these symbols. This is what typeid.name() for your compiler implementation returns. There is no requirement that the mangled name precisely relates directly to your code. Using the mangled symbol names already present in the object files for linking is a convenient implementation choice.
You can unmangle names using the c++filt tool:
Thus:
$ c++filt _FivE
yields
int ()
In other words, a function returning an int. Remember that what you are asking for here is the type of the function and not its name.
If you were to apply this to a class
class foo
{
};
cout << "foo is : " << typeid(foo).name() << endl;
You will find output is 3foo and the unmanged name foo.
The two lambdas don't unmangle. This is because they are anonymous functions, so don't need an external name.
Furthermore, compiler generates a functor class for each lambda. The first of which would look like
struct Z4mainE3
{
void operator()(int y)
{
cout << y << " ";
}
}
This means that each one is a distinct type. The name is synthetic, and generated by the compiler such that is won't collide with anything else.
The typeid operator will operate on the functor struct and not the apparent return and argument type of the lambda itself, hence the two of them are a different type despite apparently being functions having the same signature.
The long-standing advice about typeid().name() operator is that it is not portable; you should not rely on the values returned.

Resources