std::map losing track of my data? - c++

I'm sticking some data, wrapped with boost::any into a map in a class method getValue. Everything works fine, the data is in the map as appropriate etc etc in getValue. The second I leave getValue and try to use this data, it's no longer in the map.
This has me stumped, I'm probably forgetting to use a reference at a key spot, but I can't find it.
The relevant code is as follows:
test.c
//We don't want to actually document the timer, the user can do that if he wants to.
timeval tmp;
tmp.tv_sec = 0;
tmp.tv_usec = 0;
gettimeofday(&tmp, NULL);
getValue<timeval>(timerName) = tmp;
std::cout << tmp.tv_usec << " : " << getSingleton().globalValues.count(key) << std::endl; //Count returns 0 here, for a given key X_X
test.h
/* Grab the value of type T found while parsing. Should use checkValue first.*/
template<typename T>
static T& getValue(const char* identifier) {
//Used to ensure we have a valid value
T tmp;
//Used to index into the globalValues map
std::string key = std::string(identifier);
std::map<std::string, boost::any>& gmap = getSingleton().globalValues;
if(checkValue(identifier)) //If we have the option, set it's value
tmp = getSingleton().vmap[identifier].as<T>(); //vmap is correct, it specifies default values passed in via command line.
//We may have whatever is on the commandline, but what if
//The programmer has made modifications?
if(!gmap.count(key)) //The programmer hasn't done anything, lets register it then
gmap[key] = boost::any(tmp);
std::cout << "gmap " << key << std::endl;
std::cout << getSingleton().globalValues.count(key) << std::endl; //count returns 1 here, for a given key.
return boost::any_cast<T&>(gmap[key]);
}
...
test.h
//Map of global values, stored here instead of in OptionsHierarchy
//For ease of implementation
std::map<std::string, boost::any> globalValues;

On these lines you use vmap instead of gmap. Is that right?
if(checkValue(identifier)) //If we have the option, set it's value
tmp = getSingleton().vmap[identifier].as<T>();
Also I noticed that you're using count to check for existence of an item. Generally speaking unless you actually need the count, that will result in doing more work than find although for std::map it may be smart enough to optimize count into find. Since you want to insert if it doesn't exist and no-op when it does, just use insert as that's exactly the behavior insert will give you.

I fixed this, note how I define key in getValue as being std::string(identifier). In test.c I was defining key as sanitizeString(..) which returned a different key, obviously. Of course you guys couldn't see that so my bad.

Related

C++ Access violation when deferencing pointer to a class member

In my program, I'm trying to dereference a pointer to a struct Article, to get its id, but I'm getting "Access violation reading location 0xCCCCCCCC". I've tried many different things, local variables, backtracking the pointers back into the code, different parentheses... nothing though. I'm out of options and I can't see the problem however hard I try.
There might be an answer to this question, but access violation is much too general for me to be able to find the answer I'm looking for (also most of the questions go around arrays, which aren't my case).
Here I define a simple struct to keep my data.
struct Article {
public:
std::string id;
std::string title;
std::string text;
Article(std::string article_id, std::string article_title, std::string article_text) : id(article_id), title(article_title), text(article_text) {};
void toString();
};
Next, I use a dictionary that maps all words to the articles where they appear. The code is not done itself, but maps of words should include all the necessary pointers.
std::map<std::string, std::map<Article*, unsigned>> word_dict_;
I also keep another vector<Article> articles_ wher I keep all of them, so no null pointers should appear in the word_dict_;
Here the dictionary gets generated.
void fulltext::generateDict() {
for (Article ar : articles_) {
unsigned wordStart;
bool isBuilding = false;
string buffer = "";
for (unsigned int it = 0; it <= ar.text.size(); ++it) {
char c;
if (it < ar.text.size())
c = ar.text.at(it);
else
c = '\0';
if (isalpha(c)) {
// start or middle of word
if (!isBuilding) {
isBuilding = true;
wordStart = it;
}
buffer += c;
}
else {
isBuilding = false;
if (buffer != "") {
stringToLower(buffer); // rewrites buffer to low case
// Here I tried creating &ar just for the laughs and it works just fine.
word_dict_[buffer][&ar] = wordStart;
buffer = "";
}
}
}
}
}
Last but not least, I want to have it printed out and here the real fun starts.
void fulltext::printWordDict() {
cout << "Printing generated word dictionary: " << endl;
for (auto wordPair : word_dict_) {
cout << " \" " << wordPair.first << " \" " << endl;
cout << "There are " << wordPair.second.size() << " inputs." << endl;
for (pair<Article*, unsigned int> articlePair : wordPair.second) {
cout << (articlePair.first)->id << endl; // Here the access violation occurs
// Nothing seemingly works
// cout << articlePair.first->id; ... Access violation
// cout << (*articlePair.first).id; ... Access violation
// auto ar = articlePair.first; cout << ar->id; ... access violation
// auto ar = articlePair.first; cout << (*ar).id; ... access again
}
cout << endl;
}
cout << "Done." << endl;
}
These functions are called from within a main function fulltext::proccess() coincidentally in immediate succession. The word_dict_ is class private variable.
If there's need for any other parts of the code, just let me know, although none of the others should make any issues in this case.
for (Article ar : articles_) {
...
word_dict_[buffer][&ar] = wordStart;
...
}
Here you are storing a pointer to ar in your dictionary, however ar is destroyed at the end of its scope - when your for loop ends. So now you are storing a dangling pointer in your map, which you cannot de-reference.
Store Article objects in your map instead of Article* , or otherwise ensure the Article object lives somewhere as long as you have a pointer to it in your map.
If you have the objects live in your articles_ container, you might not need to copy it in your for loop, and instead do:
for (Article& ar : articles_) {
..
word_dict_[buffer][&ar] = wordStart;
Now you'll get a pointer to your Article object that resides within article_.
Though be aware what you do with article_ later on - if you perform operations on it that moves objects around (which can happen for many reasons depending on the container type), your pointers within word_dict_ becomes invalid.
for (Article ar : articles_)
This performs a copy of your article, as a local variable. This local variable goes out of scope as soon as the next iteration of the loop rolls around.
word_dict_[buffer][&ar] = wordStart;
Here you store a pointer to the local variable, that is valid only inside your loop.
If you can ensure that your articles will outlive your map, you can store a pointer to the articles stored in articles_. Take note, that if articles_ is a std::vector, it might get reallocated when you insert new articles into it, so storing pointers to object inside it has to be done carefully, making sure to invalidate them when the std::vector changes.
If all of the above sounds like your cup of tea, You most probably want to create a reference to the article, like so
for (Article& ar : articles_)
If the above sounds a bit too complicated, you have 2 possible approaches.
Make your word_dict_ map store Article objects by Value, instead of as pointers. Downside of this approach is that you store your articles twice, which has logical implications (changes to the article inside your map won't be reflected in the articles_ vector and vice-versa) as well as memory implications (you use double the memory)
Make your articles_ vector store std::unique_ptr<Article>. This way, you won't need to manually manage the reallocations inside your vector. You will still need to manage the case where an Article is removed from the articles_ vector, and make sure to remove it from the word_dict_ map. The downside of this approach is that it makes your class uncopiable by default (std::unique_ptr has a deleted copy constructor), which might or might not be a problem for you. If you need them to be copied, you would need to manually provide a copy ctor and copy assignment operator, as well manually implement or = default the other 3 special member functions (see Rule of 5)

Initialize Variables as Empty

When I have an unsigned int, but I want to find out if it is empty or not, but I need 0, I always declare it as an int and set it to -1. What am I supposed to do, though, when I need the full number spectrum or I am even working with float/double?
With some data-types it is simple, for example std::string which you can just compare to "", but is there a function to check if a variable is empty regardless of data-type, even of custom class objects?
The semantics of a value being missing are exactly why std::optional was introduced to the C++ language specification.
std::optional<unsigned int> value; // by default, the value is missing
if(value) {
// executed if the value is present, it is not
} else {
// this code is executed
}
value = 1;
if(value) {
// This code would now be executed
std::cout << "the value: " << *value << std::endl;
}
This requires a change in thinking regarding the meaning of the variable, but it forces you to think at all times regarding whether or not the variable would be present.
So for example, if you had your own class type MyClass and you wanted to retain a, potentially missing, instance of it, you would do so as follows:
std::optional<MyClass> obj; // Initially missing
obj = MyClass(); // Assigns a newly-created instance of MyClass
obj->foo(); // Calls the 'MyClass::foo' method
obj.reset(); // clears the 'obj' optional

Find unordered_map elements by searching for key struct's members values

My application have a map like std::unordered_map<my_struct *, std::string> with dozens of thousands elements. my_struct has some strings, vectors and other types members.
At some step I need to build a new my_struct and then look for the map element which has as key a my_struct having same members' values as in my lately build object.
Only way I could get it working was with an additional numeric "ID" member and replacing std::hash with custom predicate that just returns it from its operator() method. This is not a solution however. There is no way I could know that ID when looking for some element of the map.
This is the test code I wrote (test_key = my_struct):
#include <unordered_map>
#include <string>
#include <iostream>
struct test_key
{
std::size_t id; //can't exist in my application
std::string test_str1;
std::string test_str2;
unsigned int test_uint;
test_key(std::size_t id_, std::string test_str1_, std::string test_str2_, unsigned int test_uint_)
: id(id_), test_str1(test_str1_), test_str2(test_str2_), test_uint(test_uint_)
{}
};
struct test_key_hasher
{
std::size_t operator() (test_key* const& tst_k) const
{
return tst_k->id;
}
};
int main()
{
std::unordered_map<test_key *, std::string, test_key_hasher> values;
test_key *tst_k1, *tst_k2, *tst_k3, *tst_k4, *tst_lk;
tst_k1 = new test_key(1, "something 11", "something 12", 1112);
tst_k2 = new test_key(2, "something 21", "something 22", 2122);
tst_k3 = new test_key(3, "something 31", "something 32", 3132);
tst_k4 = new test_key(4, "something 41", "something 42", 4142);
values.emplace(tst_k1, "first thing");
values.emplace(tst_k2, "second thing");
values.emplace(tst_k3, "third thing");
values.emplace(tst_k4, "fourth thing");
tst_lk = new test_key(3, "something 31", "something 32", 3132); //there is no way I could know ID 3 here
std::cout << values[tst_lk] << std::endl; //Expected output: third thing
delete tst_k1;
delete tst_k2;
delete tst_k3;
delete tst_k4;
delete tst_lk;
}
I even thought that replacing key_equal on unordered_map constructor for my own predicate could solve it, but that also doesn't work (I get none of map's values as output). The key_equal replacement predicate I wrote is:
struct test_key_comp
{
bool operator() (test_key* const& tst_k1, test_key* const& tst_k2) const
{
//debug
std::cout << tst_k1->test_str1 << " == " << tst_k2->test_str1 << " ?" << std::endl;
return tst_k1->test_str1 == tst_k2->test_str1
&& tst_k1->test_str2 == tst_k2->test_str2
&& tst_k1->test_uint == tst_k2->test_uint;
}
};
Then my map looked like std::unordered_map<test_key *, std::string, std::hash<test_key *>, test_key_comp>.
The code above gives me following output when using test_key_comp in place of default key_equal:
something 21 == something 11 ?
something 31 == something 11 ?
Looks like it stops on first element...
First output line is very odd, it appears even if I don't try to find or access any element (comment std::cout line on main()).
I've also tried using find() method but result is the same as operator[] and at().
Question: any advice on why it doesn't work and how should I code it to get what I want done in a fast and efficient manner?
I want to avoid looping through all elements because there will have many of them (dozens of thousands...) and that doesn't look to be the most efficient and fastest way.
Extra question: Maybe should I use a string built from test_key's members values as the key for the map? I know that would be easier to code, but would it be more efficient and faster? Real implementation of test_key/my_struct have std::map<std::string, std::string>s, std::vector<std::string>s and a lot of members of other types (already a lot of work to compare two of those structs) and putting it all within a single string would be hard do build and parse... I know I must benchmark it, but I would like to get some hints.
You want to efficiently look up something in a hashed map by something other than the hash? That's not how they work.
You'll need to pick another data structure -- one that can sort by a something that you want to search by. It could either be a standalone data structure, or a parallel one -- potentially to your unordered_map, but you have to have something that is organized by what you want to search for or you're going to be doing an exhaustive search.

Function call is giving me the error expression must have class type

I have made a function call that in simple terms, displays the content of a list that i have values for. Here is the function definition:
void display_list(list<string>*type_list)
{
cout << "You made a function call" << endl;
for (list<string>::iterator dis = type_list.begin(); dis != type_list.end(); ++dis)
{
cout << *dis;
cout << "\n";
}
}
All this is supposed to do is make it easier on me, because there are numerous times throughout my code that i have to display the contents of a list, so i tried to make it easier on myself and make a function call for it so all i have to do is make the function call:
display_list(&list_name_here);
although everything works fine, as you can see i added a test 'cout' to make sure the function call works correctly, but it doesn't display the contents, and i get an error that highlights the
type_list
and error pops up that says expression must have class type?
Now I did change the code to look like this:
void display_list(list<string>*type_list)
{
cout << "You made a function call" << endl;
list<string> gen;
*type_list = gen;
for (list<string>::iterator dis = gen.begin(); dis != gen.end(); ++dis)
{
cout << *dis;
cout << "\n";
}
}
In this form i dereferenced type_list into a local variable, and then proceeded as normal.. As this method does get rid of the class type error, but when i compile and run it, nothing get displayed from the list.. The list is really simple so it should only display like 10 values.
Now in case you are asking, that original algorithm when placed in my main code and i replace the type_list with the appropriate list names, the code then works perfectly and designed. To display the contents of the list. So i know my error isn't in that.
Can anyone please shed some light on this?
You need to use the -> to access members and member functions from a pointer.
void display_list(list<string>*type_list)
{
cout << "You made a function call" << endl;
for (list<string>::iterator dis = type_list->begin(); dis != type_list->end(); ++dis)
{
cout << *dis;
cout << "\n";
}
}
As for the problem of an empty list in your second attempt,
list<string> gen;
*type_list = gen;
sets *type_list to gen but it doesn't change gen. gen is an empty list and you proceed to iterate on it.
You could have used:
list<string> gen = *typ_list;
or (thanks, #MattMcNabb)
list<string>& gen = *typ_list;
In the line:
*type_list = gen;
you are changing type_list to point to gen. Note that gen is empty at this point.
Also, later you use an iterator from gen in the for loop, despite nothing being in it.
You might have meant that line to read:
gen = *type_list;
gen is unnecessary though, you can just get an iterator from type_list directly.
I'm confused. Your function display_list doesn't really do anything.
Here's my inspection of your function.
Pass by const reference
Large data structures should be passed by constant reference, unless you plan to modify it. A display function should not be modifying its argument:
Was:
void display_list(list<string>*type_list)
Change to:
void display_list(const list<string>& type_list)
Copying an empty list deletes the existing list
This line creates an empty list called gen.
list<string> gen;
This line copies the empty list to the list passed:
*type_list = gen;
Iterating an empty list has no functionality
Since the gen list is empty because you newly created it, this loop doesn't have any functionality.
for (list<string>::iterator dis = gen.begin(); dis != gen.end(); ++dis)
{
cout << *dis;
cout << "\n";
}
What are you trying to do?
Do you really need to copy a list before printing it?
(Copying a list for no reason is a waste of data and execution time.)
Why are modifying the list you passed?
I'm confused.
Edit 1:
The code to display a list:
void display_list(const std::list<string>& type_list)
{
std::list::const_iterator iter;
for (iter = type_list.begin();
iter != type_list.end();
++iter)
{
std::cout << *iter << "\n";
}
}
See: no need to create a new list or copy the old list.
The function doesn't modify the list, based on the const in the parameter list and using the const_iterator.
Since the list is passed by reference, no pointers, no dereferencing issues.
The . operator is only for using on objects. To look up members on an object that you are pointing to, either write (*ptr).name, or equivalently ptr->name .
Example:
string s;
string *ptr = &s;
cout << s.size() << "\n";
cout << ptr->size() << "\n";
Having said that, a better fix would be for you to pass your list by reference, instead of passing by pointer:
void display_list(list<string> &type_list)
Then you use the . syntax.
Even better would be to pass by const reference; then you use const_iterator also.

Problems with pointers in a list

For some reason when I try and read a property of a pointer to an object(GamePlayer) within an std::list (playerlist) it works at first, but when I try to access it later in another function I get a bunch of random numbers instead of the numbers for my client's socket. That was a mouthful, sorry. I hope someone could shed some light on the situation. I will include a simplified version of the defective code.
class GameRoom {
list<GamePlayer*> playerlist;
locigPort( LogicObj );
}
bool GameRoom::logicPort( LogicObj logit ) { // This is room[1]
list<GamePlayer*>::iterator it;
for (it = playerlist.begin(); it != playerlist.end(); it++){
cout << "socket numbers " << (*it)->socketno << endl;
/* (*it)->socketno gives me a bunch of random numbers,
not the socket numbers I was looking for! */
}
return true;
}
bool RoomDB::addPlayer( GamePlayer *playerpoint ) {
roomlist[1].playerlist.push_back( playerpoint );
// This adds the player object to the Gameroom object
cout << "player point " << playerpoint->socketno << " roomno: " << roomno;
// This shows everything should be ok so far
return true;
}
The most likely explanation is that you're calling addPlayer with a pointer than becomes invalid by the time you call logicPort. One possibility is that you call addPlayer with the address of an object on the stack, and the object disappears when the stack is unwound.
edit The problem is right here:
bool PlayerDB::addPlayer( int sid, GamePlayer tempplayer ) {
...
roomman.addPlayer( &tempplayer, tempplayer.roomno );
}
PlayerDB::addPlayer takes the second argument by value. This means that it gets a copy that exists for the lifetime of the method. You then take the pointer to that copy, and add it to the list. Once PlayerDB::addPlayer returns, the pointer becomes invalid.
It's hard to suggest a good fix without seeing more code. One possibility is to make PlayerDB::addPlayer take a pointer as its second argument, and make sure you don't repeat the same mistake one level up the call chain.
An even better possibility is to turn playerlist into list<GamePlayer>: from your code there doesn't appear to be any need for the list to contain pointers. This will simplify things greatly.