VS2013 C++: Map - Unhandled Exception, Out of Range - c++

I'm trying to create a function that keeps track of recently used addresses, using a vector of maps for each index. Each time the address (used as the map key) is found, it would update the key member variable value. If its not a mapped value in the table, it will add it. That way I can keep track of older vs. newer addresses. Initially I tried to code it in the following manner:
int key = 0;
void update(uint32_t address, int index, vector<map<uint32_t, int> >& table)
{
auto search = table.at(index).find(address);
if(it != table.at(index).end())
{
table[index][address] = ++key;
}
else
{
table.at(index).insert(make_pair(address, ++key));
}
}
However, every time I go to test my function, VS2013 always throws an unhandled exception error informing me that the Unhandled exception was thrown because std::out_of_range when it gets to the auto search line. I figured the error was thrown because the map starts off initially empty, and there are no maps available for it to search through for any addresses. So then I modified it to determine first if the table is empty, if so insert the first pair, otherwise if its not, search the table for the address value, and update the key:
int key = 0;
void update(uint32_t address, int index, vector<map<uint32_t, int> >& table)
{
if(table.at(index).empty())
{
table.at(index).insert(make_pair(address, key));
}
else
{
auto search = table.at(index).find(address);
if(it != table.at(index).end())
{
table[index][address] = ++key;
}
else
{
table.at(index).insert(make_pair(address, ++key));
}
}
}
But then the same exception occurs at the if(table.at(index).empty()) line. Then I scaled it down, just to see if I could just simply capture and store any maps at all:
int key = 0;
void update(uint32_t address, int index, vector<map<uint32_t, int> >& table)
{
table.at(index).insert(make_pair(address, ++key));
}
And that generates the same unhandled exception also at table.at(index).insert(make_pair(address, ++key)).
Not only that but I've tried determining if the table.at(index) == NULL or nullptr or 0. Looked for alternative means of adding the map pairs to the vector, instead of using insert. Unfortunately, the options I was looking at don't exist for map (i.e. assign or push_back). I also looked into implementing a try-catch statement, but wasn't exactly sure on how to code it, especially with the "throw" keyword.
I have no idea what could be causing this issue. Does anyone have any suggestions on what could be the problem? Or what I'm doing wrong? Maybe my program doesn't like my vector of maps possibly?
Thank you!

Related

searching for a key in a bst

the compiler is telling me that the assertion failed even though I have atleast 2 items in the array of linked nodes. How do I fix this bool contains function? And yes, I have tried multiple ways but I still get the same error.
Keep in mind that there are 2 items in different indexes of the array. But its not shown below.
This is the contain function:
bool Map::contains(string key){
bool idk = false;
if(elementsStoredCount != 0){
int idk = hashFunc(key); //the hashFunc computes using modulo
if(array[found] != nullptr){
idk = false;
}
else{
found = true;
}
}
return found;
}
when I test in my main.cpp, the second line fails for some reason.
assert(as.contains("1")==true);
Based on some of the other comments and reading the code, i would think that your problem is that your int hashFunc(string key) function is returning an incorrect index outside of the range of array[].
Have you debugged/tested taht the hashFunc() function to ensure the correct data? If correctly implemented and still you are facing a bug, then i'd next look at your table data/insertion functions.

C++ map, find element and insert it into another map (without copying)

How to correctly find element from source map and insert it into another map?
std::map<int, std::shared_prt<Obj>> src_map
std::map<int, std::shared_prt<Obj>> target_map
int key = 6;
auto found_elem = src_map.find(key);
if (found_elem != src_map.end()) {
if (target_map.find(key) == target_map.end()) {
target_map.insert(found_elem ); <---- How to correctly insert found element from src_map to target_map
}
}
target_map.insert(found_elem);
found_elem is an iterator, you need to insert the value it refers to:
target_map.insert(*found_elem);
Also this could be done more efficiently:
if (target_map.find(key) == target_map.end()) {
target_map.insert(found_elem);
}
You do the lookup twice. Once in find and again in insert.
It's better to just try to insert it, and if you need to know whether it was inserted check the return value:
auto inserted = target_map.insert(*found_elem);
// inserted.first is the iterator to the element with the desired key
// inserted.second is true if a new element was inserted, false if the key already existed
Other options for putting it in the map are to find the position where it belongs, then insert at that position if it's not there already:
auto lower = target_map.lower_bound(key);
if (lower == target_map.end() || lower->first != key) {
target_map.insert(lower, *found_elem);
}
Another option is:
auto& val = target_map[found_elem->first];
if (!val)
val = found_elem->second;
but this is not exactly the same, because if the key already exists in the map with an empty shared_ptr as the value then the value will get replaced. Depending whether you can have empty shared_ptr objects in the map that might not be correct for your program.
Yet another, with slightly different meaning again, is:
target_map[found_elem->first] = found_elem->second;
In current declaration
std::map<int, Obj> src_map
std::map<int, Obj> target_map
You can't have one Obj instance in memory connected to both maps. Either you remove Obj from src_map and put in target_map or change declaration to;
std::map<int, Obj*> src_map
std::map<int, Obj*> target_map
or any other pointer type (shared_ptr as suggested in comment), without this you will always have two independent objects in memory.

confusion over using upgradable lock on std::map's find/insert

Consider a thread-safe getter method in its,relatively, simplest form:
std::map<std::string, boost::shared_ptr<AAA> > repo;
AAA & get(const std::string &key)
{
boost::upgrade_lock<boost::shared_mutex> lock(repoMutex);
std::map<std::string, boost::shared_ptr<AAA> >::iterator it = repo.find(key);
if(it == repo.end()){
boost::upgrade_to_unique_lock<boost::shared_mutex> uniqueLock(lock);
boost::shared_ptr<AAA> t(new AAA(key));
repo.insert(std::make_pair(key,t));
return *t;
}
return *it->second;
}
in above, I use a shared(upgradeable) lock to protect a find operation, and upgrade to unique lock only if I need to insert a key/value. So far so good?
What I imagine is the following(please let me know if in any step my concept is wrong):
Two threads enter the method
Both are allowed to run repo.find() for the same key at the same time(and the key doesn't exist).
Both of them fail.as the key doesn't exist .
first thread gets exclusive access by entering the upgraded area, while the second thread waiting to enter upgraded area.
first thread finishes its job of creating a new entry for key and then
walks off.
second thread enters and overwrites the key/value inserted by the first thread.(which is not what anybody wants)
How do we solve this issue? thanks
In short, there's almost nothing wrong with your current solution.
First of all, the second thread won't overwrite the data written by the first one, because map::insert() inserts only new keys. You only have to check if insert really inserted the element and return corresponding value.
The only concern is possible unwanted creation of t for nothing. In this case you can add another check after locking:
std::map<std::string, boost::shared_ptr<AAA> >::iterator it = repo.find(key);
if(it == repo.end()){
boost::upgrade_to_unique_lock<boost::shared_mutex> uniqueLock(lock);
if (repo.find(key) == repo.end() {
...
}
}
But you should profile your code to see if this gives you any advantage.
Also, you can utilize map::insert() with hint to avoid double searching for the key:
std::map<std::string, boost::shared_ptr<AAA> >::iterator it = repo.find(key);
if(it == repo.end()){
boost::upgrade_to_unique_lock<boost::shared_mutex> uniqueLock(lock);
it = repo.lower_bound(key);
if (it->first != key)
boost::shared_ptr<AAA> t(new AAA(key));
repo.insert(it, std::make_pair(key,t));
return *t;
} else {
return *it->second;
}
}

Iterator over a list pointing to wrong elements

I have 2 variables: std::list lst; and std::list<A*>::iterator lstiter with A being a class. The lst is filled with pointers to the class! B is an other class that holds both variables.
Puts iterator at the begin of the list:
void B::iterstart() {
lstiter = lst.begin();
}
void B::iternext() {
iteratend();
lstiter = ++lstiter;
}
void B::iterprev() {
iteratstart();
lstiter = --lstiter;
}
void B::iteratend() {
if (lst.empty())
throw -1;
if (lstiter == lst.end())
throw "Error: end of list\n";
}
void B::iteratstart() {
if (lst.empty())
throw -1;
if (lstiter == lst.begin())
throw "Error: begin of list\n";
}
(I also have a function that gets the pointer at the element in the list the iterator is pointing too at the moment. Iteratend and iteratstart throw an exception when there are no elements in the list and when I try to go past the last or first element. This is where my problem is!
Now I call: iterstart(); iternext(); iternext(); iternext(); I never get the message!(End of list)
And I do have some other bugs too, Sometimes I call the procedure prev, but I get the return value of the procedure next! (But I want to try to solve the other problem first)
This lstiter = ++lstiter is wrong. With an integer it might work but when used with complicated C++ objects it does not always perform correctly because it depends on the specific implementation of the increment and copy functions. Also, why would you want to do it? All you need is ++lstiter.

Programming error in allocating new stack

I am writing a program to implement a stack which works like a real world stack means it topples when the size of a stack reaches threshold and therefore need to create a new stack for inserting that new element.
Below is my program for this:
#include <iostream>
#include<vector>
#include<stack>
using namespace std;
class stack_of_plates
{
vector<stack<int> > stacks;
unsigned int stack_size;
public:
stack_of_plates(unsigned int size=100)
{
stack_size=size;
}
void push(int data)
{
if(stacks.empty())
{
stack<int> *sptr= new stack<int>; //on debugging Segmentation fault at thisline
stacks.push_back(*sptr);
}
vector<stack<int> >::iterator it=stacks.end();
if(it->size()==stack_size)
{
stack<int> *sptr= new stack<int>; //on debugging Segmentation fault at thisline
stacks.push_back(*sptr);
}
it->push(data);
}
void pop()
{
if(stacks.empty())
{
cout<<"\nEmpty Stack";
return ;
}
vector<stack<int> >::iterator it=stacks.end();
if(it->empty())
{
it--;
}
it->pop();
}
int top()
{
if(stacks.empty())
{
cout<<"\nEmpty Stack";
return 0;
}
vector<stack<int> >::iterator it=stacks.end();
if(it->empty())
{
it--;
}
return it->top();
}
};
int main()
{
stack_of_plates ss;
ss.push(1);
ss.push(2);
cout<<ss.top();
return 0;
}
On compiling it gives no error or warning. However program terminates with unusual error.
On debugging its giving segmentation fault error indicating problem in allocating new stack.
Kindly help me how should i change my code while allocating the new stack. Please help me removing this error.
stacks.end(); refers to the (nonexistent) element after the end of the vector. You can't dereference it; doing so will cause undefined behaviour, possibly a segmentation fault.
It's not quite clear what you're doing there, but if you want an iterator for the last element, then either decrement it:
vector<stack<int> >::iterator it=stacks.end(); // points past the end
--it; // points to last element
or use a reverse iterator (in which case, you use ++ rather than -- to move backwards through the sequence):
vector<stack<int> >::reverse_iterator it=stacks.rbegin();
Adding an element to a vector can invalidate it, so the it->push_back(data) at the end of push() is incorrect. You could avoid using an iterator here:
void push() {
if (stacks.empty() || stacks.back().size()==stack_size) {
// See below for explanation of this change
stacks.push_back(stack<int>());
}
stacks.back().push(data);
}
In pop(), you probably want to remove the last stack if it's empty; otherwise, you'll end up with two empty stacks at the end, and your code will erroneously try to pop from one of those. Again, doing that could cause a segmentation fault or other undefined behavoiur. You probably want something like:
void pop() {
if (stacks.empty()) {
cout<<"\nEmpty Stack";
return ;
}
stacks.back().pop();
if (stacks.back().empty()) {
stacks.pop_back();
}
}
And now we've established an invariant that the last stack is never empty, top can be a bit simpler:
int top() {
if (stacks.empty()) {
cout<<"\nEmpty Stack";
return 0;
}
return stacks.back().top();
}
Also, you usually don't want to create objects using new, especially in a case like this where you're putting a copy of the object into the vector and then discarding the pointer, leaking the allocated memory. You can add an empty stack to the vector like this:
stacks.push_back(stack<int>());
Sometimes (but not in this case) you might want to store pointers to allocated objects in a container; in that case, either remember to delete them when they're removed from the container, or store smart pointers such as std::unique_ptr. But in this case, just store objects.
There are many problems with the code, so it is hard to say which one is the direct cause of your problem. You need the clean them up one by one and then retest. If you still have a problem, post your new code here.
Here is the list:
You have a memory leak from your allocation with new. Since you have a vector of stacks, all you need to do is resize the vector and a new stack will be allocated. So
stacks.resize(stacks.size() + 1);
instead of
stack<int> *sptr= new stack<int>;
stacks.push_back(*sptr);
vector<>.end() returns an iterator that point to an element AFTER the last one, which is why #Joachim suggested that you need to decrement the iterator before you use it.
You have a logical error when you check whether to transfer storage to a new stack - after checking is the size of the last stack is the max, and creating a new one, you keep pushing on the old one.
I hope this helps.
std::stack<int> already has the functionality you show in your example, so there is no need for a std::vector< std::stack<int> >. By just pushing and popping to the std::stack<int> you avoid most of the issues your having in your code. There is no reason to limit std::stack<int> to stack_size.
Next to that, when you need the last entry in a container, use back() instead of end().