Insert new element into hash table? - c++

auto iterator = unorderedMap.find(element);
if (iterator == unorderedMap.end()) { //If the element doesn't already exist in the table, create a new entry
iterator = unorderedMap.insert(make_pair((element), vector<unsigned>()).first;
}
iterator->second.push_back(unsigned_number_associated_with_element);
The hashtable is a table of strings and vector<unsigned> (the key is of type string).
element is of type of string.
The code is supposed to do the following:
1) Check if the key element exists in the hash table
2) If it doesn't, create a new entry. If it does, just do the next step.
3) Push element into the entry's vector.
The code compiles fine, but running it gives me an error:
error: attempt to subscript container
with out-of-bounds index 22464, but container only holds 22464 elements
Anyone know why? Commenting out the last line makes the error go away.

I honestly don't know where that error was coming from (although I suspect that it was some sort of unfortunate parenthesization error), but there is no difference between the intent of that code and the following rather simpler code:
unorderedMap[element].push_back(unsigned_number_associated_with_element);
except that the above is probably faster (it will only do one lookup rather than two if the element isn't present) and is certainly easier to read and debug.

Related

How to store array data as map key or increment frequency if array already in map?

My code:
map<array<byte, aes>, int> possible;
array<byte,aes> temp;
if (!possible.count(temp)) // if not found
possible.insert(pair<array<byte,aes>,int>(temp,1)); // insert
else
possible[temp]++; // if found increment frequency
I need to use an array with its data as a map key. An integer indicates the frequency of occurrence of the array. However, the new array is only written the first time, the other times the code considers it to be the same array. As I understand it, the program takes the address of the array, not its data. How to pass an array with data to the map instead of the address of the array?
I know that in Qt this code works fine:
QMap<QByteArray,int> possible;
QByteArray temp;
if(!possible.count(temp)) // if not found
possible.insert(temp, 1); // insert
else
possible[temp]++; // if found increment frequency
What is alternative for std::array and std::map to do this?
In C++ this code will work fine
possible[temp]++;
If temp exists then it's frequency will be incremented. If it does not exist then it will be inserted with a frequency of 0, which will then be incremented. This gives you exactly the same result as your code.
Looking at the documentation for QMap, it seems the above code would also work on Qt.
Sometimes (not often) things are easier than you imagined.

What is the difference between [] operator and erase function while using an unordered map in c++?

I created an unordered map in C++, and used umap.erase(num) = 0 to delete the element from my hash table. This was functioning in a loop and gave me a Time Limit Exceeded error, but when I used umap[num] = 0 instead, to perform the same task, it worked. Do these two have such a huge difference in time complexities as to give me an errors? If yes, how much is this difference?
Ignoring the fact that the first expression produces a compile time error, since you cannot assign something to the value returned from umap.erase(num) (the return type is size_t) the difference is the following:
erase removes the key-value entry from the map completely. For any further access to the key an entry associated with the needs to be created. This may result in unnecessary updates on the map that decrease performance (rehashing, allocation of the the objects required to store the entry. Furthermore using erase you never create a new mapping; calling erase with a key not associated with a value simply leaves the map unchanged.
umap[num] = 0 simply sets the value associated with num to 0, but keeps the mapping; this may actually create a new mapping, should there be no value associated with num before the operation.
To highlight the difference
umap[num] = 0;
//umap.erase(0);
auto iter = umap.find(num);
bool mappingExists = (iter != umap.end());
Both options will result in different values for mappingExists: umap[num] = 0; will yield true and umap.erase(0) will yield false.
Note that given the information in the question it's impossible to tell, if both versions of your algorithm are even equivalent. They may very well be, since accessing a non-existing mapping via operator[] results in an initialization of the value with the default value, which is 0 for integral types.

Assertion failure: list iterator not incrementable (not in a loop)

First off, good morning/day/evening and thank you to whoever is taking their time to read this.
The Setup:
In my code I have two different classes: ColObj and QuadNode (that is, the 'collision object' and a node in a quad tree used to check for proximity of objects. I know there are probably libraries out there for this, but I need to write my own system, so they would be of no use here). Things work like this: When a ColObj object is created, it is added into an appropriate QuadNode (the node has a std::list of pointers to ColObj), so that the node can inform it when it collides with something; the ColObj object also receives a pointer to the node that's holding it and a list iterator to the list iterator containing its address so when it's out of the node's bounds or gets destroyed it can 'leave' it, and clean up the node, that is, remove and reference to itself from the node. I made it like this because in a lot of cases it's going to be a frequent operation and I want it to be in constant time.
The Code:
This is the method used to 'attach' a ColObj to a QuadNode. I suspect the problem is not in here.
void QuadNode::obj_add(ColObj *obj) {
std::cout<<"QuadNode at depth ("<<depth<<") received new ColObj.\n";
objects.push_back(obj);
obj->holder = this;
obj->my_iter = std::prev( objects.end() );
if ((int)objects.size() > MAX_OBJECTS && depth < MAX_DEPTH) split();
}
This is the QuadNode method that a ColObj uses to clean up the node. Here is where the problem occures for some reason.
void QuadNode::obj_list_erase(std::list<ColObj*>::iterator iter) {
std::list<ColObj*>::iterator iter2 = objects.begin();
objects.erase(iter);
}
The first line in this method is simply to provide additional information for debugging and will be removed afterwards.
The Error:
The strangest part is that, for the most part, the code works fine. Then at one point, randomly, it throws an assertion failure, saying that a "list iterator is not incrementable". That's the first strange thing, I'm not trying to increment it anywhere in my code (though I know that std::list::erase returns the following iterator, but I never attempt this operation on an invalid or "past-the-last" iterator).
Anyway, Visual Studio offers to fire up the debugger and put a break point in the code, so naturally I agree. So here's the weirdest part:
Local and auto variables, debugger screenshot
(I can't embed an image since I'm new here, so it is what it is).
So, unless I'm gravely mistaken here, it's telling me that the passed iterator is equal to be beginning iterator of the list, that its element is still present in the list and corresponds to the first (or rather zero-th) element of the list. And yet, the erase() method fails.
For what it's worth, I've noticed that every single time the program breaks, the passed iterator points to the zero-th element of the list, though I can confirm that the method usually works even when there's only one element in the list.
Additional info and conclusion:
I'm not manually incrementing the iterator anywhere else in the code (which is pretty small and simple anyway).
The IDE I'm using is Visual Studio Community 2015, but I don't know the compiler version. (Microsoft and their naming schemes...)
I tried finding another thread about this on SO but every one I checked was about wrongly placed i++ in list iterations, so sorry if this is a duplicate thread.
I'm completely confused by this problem, because usually between the excellent debugger, std::cout and browsing SO I somehow fix the issue, but this time around nothing useful is coming up, so any advice or suggestion would be very welcome.
Edit:
One thing I have tried "just 'cause" editing the QuadNode::obj_list_erase method so that it compares the passed iterator with the first iterator of its list (objects.begin()) and if they're equal use objects.pop() to remove it, else erase it normally. It didn't work, saying that the iterators weren't compatible, whatever that means...
After finding out that I cannot even compare the passed iterator with any other iterator from the list that was supposed to be holding it (I was getting Assertion failure: iterators not compatible), I searched SO for more info on what it means, and... Andrew Kashpur was right. I did manage to invalidate an iterator by removing the pointed element from the list and putting it back immediately, but without updating the iterator.
Moral of the story: An iterator can seem to point to a "correct" memory location, it may even point to the same address as some valid iterator does, but that does not make it valid or compatible.

Last array element in a row and first element in the next row having the same pointer

I was working on a college assignment that required me to get a mathematical equation related to array pointers, I wrote the following code to display the pointers of all elements:
It was all smooth until I decided to convert the addresses to decimal to make my calculations easier, I used the following line of code:
size_t D = reinterpret_cast<size_t>(&X);
Once I did, somehow the last element in a row and first element in the next row returned the same address:
Even after I removed that line and restored my code to it's previous state, the specified elements still return the same address. I thought it might be a weird Visual Studio behavior and I tried restarting it, but the issue wasn't fixed. I'm wondering how this happened and how it can be fixed, it doesn't make sense.
The size of your array was changed to Arr[5][4]. It won't return an error or warning as, they are all valid pointers to the 'one past the end' element of an array.

deleting elements completely from multimap (C++)

So I have a multimap, where the key is a struct, and the values are another struct.
multimap<struct, struct> multimap1;
multimap1 contains (format is key: value)
1: Random Value 1
2: Random Value 2
3: Random Value 3
4: Random Value 4
I am trying to erase a value and a key from the multimap. Let's say I want to remove the second entry of the multimap. The result should be this:
1: Random Value 1
3: Random Value 3
4: Random Value 4
I have an iterator that points the second value, so when I erase it using multimap1.erase(it), it should remove the second entry (at least I think it should). I have been reading up on removing entries and from multimaps and it seems that only the value is removed from the multimap, not the key. So if erase the second entry with an iterator pointing to the second value, it would do this (Correct me if I am wrong):
1: Random Value 1
2:
3: Random Value 3
4: Random Value 4
Is there a way to get the middle value result?
Edit: So I am apparently wrong. If you do erase, you do get the middle result. I am trying to figure why I am not erasing correctly because, my code segfaults when I call the erase. If I call it->first, it returns the key of the element I want removed. If I call it->second, it returns the value of that key. So if I call multimap.erase(it), It should remove the entire thing, correct?
Edit 2: In my code, I printed out it->first and it->second to make sure that the pointer was pointing to the correct element and it was. When I called multimap.erase(it), I stopped the loop and printed out the remaining elements in the multimap. It prints the first element correctly, but then the second element is printed something like this (output from compiler):
GEWolfC?`6??2?x3??2??2?x 1#4?????BUYA????BadWolfCorp1????AMstyKrq?4?X3??(4??3?
X3PlanetExpress1GEqp7?L???5?d?5?x5??5?d2q7?7?X3??(4??3?X3??
So obviously, it is not deleting correctly. I am running g++ 4.7 on linux.
Edit 3: Sorry for so many edits, I want to keep the original question so people can reference it in the future. Just to experiment, I called multimap.erase(it->first) and that worked correctly. Can someone explain to me why this worked and what is going on here?
erase does remove the whole entry (the "key-value" pair), as you want.
Sometimes, confusion arises when talking about map types since the library specification defines value_type to mean the "key-value" pair, not just the "value" (which is defined as mapped_type); so the word "value" is used interchangabley to mean one or the other.