I've been trying to use a hash_multimap for sometime now, but the find method keeps giving me a iterator to the end of the container even though I know it found a matching key. What has me confused is that I've used the same code before for a different project with it working perfectly but now its playing up. The reason I know its finding something is because I've put a few cout in the hash function and hash compare, which is telling me that a key is found and that it matches what I gave the hash_multimap::find meathod, yet still it gives me an iterator.
first the header file
//
// HashGrid.h
// Planetarium
//
// Created by Taura J Greig on 24/08/12.
// Copyright (c) 2012 __MyCompanyName__. All rights reserved.
//
#ifndef _HASHGRID_
#define _HASHGRID_
#include <iostream>
#include <hash_map>
#include <deque>
#include "..//hashKey.h"
struct myTraits
{
static const size_t bucket_size = 4;
static const size_t min_buckets = 8;
myTraits() { };
myHash hashfunction;
myEqualTo equal_to;
size_t operator() (const hashKey& key) const
{
size_t hashval = 0;
hashval = ((key.y * globalGridWidth) + key.x);
cout << "x : " << key.x << " y : " << key.y << endl;
cout << "hashVal : " << hashval << endl;
return hashval;
}
bool operator() (const hashKey& key1, const hashKey& key2) const
{
bool test = (key1.x == key2.x && key1.y == key2.y);
cout << "equal_to = " << test << endl;
return test;
}
};
using namespace std;
//using namespace stdext;
using namespace stdext;
template <class T>
class HashGrid
{
public:
typedef deque<T *> localObjects;
typedef pair<hashKey, T *> addingPair;
typedef hash_multimap <hashKey, T *, myTraits> hashmMap;
typedef typename hash_multimap <hashKey, T *, myTraits> :: iterator hashmMapItor;
typedef pair<hashmMapItor, hashmMapItor> valueRange;
private:
hashKey keyOffsets[9];
int gridSize;
hash_multimap<hashKey, T*, myTraits> theMap;
inline bool exists(hashKey & theKey);
inline bool exists(hashKey & theKey, hashmMapItor & it);
public:
HashGrid();
void setup(int gridSize);
void update();
void draw(); // this is used for viusal debug,
void resize();
void addObject(T * object);
void getLocalObjects(float & x, float & y, int range, localObjects & p1);
};
template <class T>
inline bool HashGrid<T>::exists(hashKey & theKey)
{
hashmMapItor it;
it = theMap.find(theKey);
if (it == theMap.end())
{
return false;
}
else
{
return true;
}
}
template <class T>
inline bool HashGrid<T>::exists(hashKey & theKey,
hashmMapItor & it)
{
it = theMap.find(theKey);
if (it == theMap.end())
{
return false;
}
else
{
return true;
}
}
#include "HashGrid.cpp"
#endif
and the source file
//
// HashGrid.cpp
// Planetarium
//
// Created by Taura J Greig on 26/08/12.
// Copyright (c) 2012 __MyCompanyName__. All rights reserved.
//
#ifndef _HASHGRID_SOURCE_
#define _HASHGRID_SOURCE_
#include "HashGrid.h"
#include "ofMain.h"
template<class T>
void HashGrid<T>::update()
{
theMap.clear();
}
template <class T>
void HashGrid<T>::addObject(T *obj)
{
hashKey tempKey;
tempKey.x = int(obj -> getPos().x) / gridSize;
tempKey.y = int(obj -> getPos().y) / gridSize;
cout << "tempKey.x : " << tempKey.x << endl;
cout << "tempKey.y : " << tempKey.y << endl;
theMap.insert(addingPair(tempKey, obj));
}
template <class T>
void HashGrid<T>::getLocalObjects(float & x, float & y, int range, localObjects & p1)
{
cout << "you are gettin local objects" << endl;
int gridX = (int(x) / gridSize);
int gridY = (int(y) / gridSize);
cout << "player x : " << x << endl;
cout << "player y : " << y << endl;
cout << "girdX " << gridX << endl;
cout << "girdY " << gridY << endl;
for (int i = 0; i < 9; i++)
{
hashKey tempkey;
tempkey.x = gridX;
tempkey.y = gridY;
tempkey += keyOffsets[i];
cout << i << " tempKey : " << tempkey.x << " " << tempkey.y << endl;
cout << "exists " << exists(tempkey) << " ";
//this is where the problem lies, the exists function will always return
//false even when the key is found
if (exists(tempkey))
{
cout << "found" << endl;
hashmMapItor it;
valueRange elements;
elements = theMap.equal_range(tempkey);
for (it = elements.first; it != elements.second; it++)
{
p1.push_back(it->second);
}
}
else
{
cout << "not found" << endl;
}
}
}
#endif
Note that I've cut a lot of methods out of the block above to save space because they are unrelated to the problem at hand. However I've left their declarations in the header file. Also I am aware that there a few things that I'm doing with templates that are ugly. Just deal with it for now.
Now I'll go into detail about whats happening in the code and where the problem lies. In the getlocalobjects method, the method "exists(key)" is called to determine if the hash_multimap has an element with the key provided. I know that it does find something because as I mentioned above because I put cout in the equal_to function to tell me when its used an what its result are.
Consistently its telling me yes (via equal_to debug) it found something but the exist method will still return false. This leading me to believe that there may be a bug in hash_multimap::find since it means that even if it finds something its gives me an iterator to hash_multimap::end
So my question is am I doing horribly wrong regarding the use of the multimap? does my traits struct not have something required for the multimap to work correctly
EDIT and the implementation for the hashKey that i forgot it include
header
#ifndef _HASHKEY_
#define _HASHKEY_
#include <iostream>
using namespace std;
static int globalGridSize = 1;
static int globalGridWidth = 1;
static int globalGridHeight = 1;
struct hashKey
{
public:
int x;
int y;
hashKey();
hashKey(int x, int y);
void set(int x, int y);
void set(hashKey & key);
void printKey()
{
cout << x << " " << y << endl;
}
bool operator < (const hashKey & key1) const;
bool operator == (const hashKey & key1) const;
hashKey& operator += (hashKey & key1);
};
#endif
and source
#ifndef _HASHKEY_SOURCE_
#define _HASHKEY_SOURCE_
#include "hashKey.h"
hashKey::hashKey()
{
x = 0;
y = 0;
}
hashKey::hashKey(int x, int y)
{
hashKey::x = x;
hashKey::y = y;
}
void hashKey::set(int x, int y)
{
hashKey::x = x;
hashKey::y = y;
}
void hashKey::set(hashKey &key)
{
x = key.x;
y = key.y;
cout << "set: x = " << x << " y = " << y << endl;
}
bool hashKey::operator<(const hashKey &key1) const
{
if ( (this->x < key1.x) && (this->y < key1.y))
{
return true;
}
return false;
}
bool hashKey::operator == (const hashKey &key1) const
{
if ((this-> x == key1.x) && (this->y == key1.y))
{
return true;
}
return false;
}
hashKey& hashKey::operator+=(hashKey &key1)
{
this->x += key1.x;
this->y += key1.y;
return *this;
}
#endif
EDIT [SOVLED] I changed the hash_multimap tp an unordered_multimap and now it works, so initial suspicion was right, that at this time the hash_multimap is bugged an its find method will always give an iterator to the the end. Note that i'm using visual studio c++ 2010, it may not be bugged on other platforms or other compilers, however it defiantly was bugged in my case
The content below is speculation as not all the relevant code is visible.
It seems that you have:
A hash which is of type size_t (as created from the first operator() of myTraits)
A key of type hashKey (which is not a hash from the hash_multimap's perspective)
You did not provide the implementation of hashKey, so my immediate question is:
Did you provide the equality operator for hashKey?
Or alternatively, did you override equal_to<haskHey>?
The potential problem (and reason for the above questions) that I see is that you defined your hashmMap as hash_multimap <hashKey, T *, myTraits> which overrides the hashing function, but it does not override the key equality (which is of type hashKey). So, I presume that the default comparator of hashKey (and not the one defined in myTraits) might be used.
Perhaps hash_multimap <hashKey, T *, myTraits, myTraits> would suffice?
Update: I just notice that VS's hash_multimap has a different signature, than the one coming from STL. Compare:
Visual Studio version
STL version
The latter has hashing function and key comparator separated. This is just asking for terrible problems once you switch compilers!
Related
I am learning templates and am struggling to set up my put method without compiler errors. Can someone point me in the right direction? The commented sections are not implemented yet, but based on an Integer-key, String-value implementation.
The concrete error I am having: Severity Code Description Project File Line Suppression State
Error C2923 'HashTable<int,std::string>::HashItem': 'key' is not a valid template type argument for parameter 'Key'
#pragma once
#include <cmath>
#include <iostream>
#include <list>
using namespace std;
template<typename Key, typename Value>
class HashTable
{
template<typename Key, typename Value>
class HashItem {
public:
Key key;
Value value = nullptr;
bool operator==(const HashItem& hi) const { return key == hi.key && value == hi.value; }
HashItem(const Key& k, const Value& v)
: key(k), value(v) {}
// for part b)
HashItem& operator=(const Value& v) {
this->value = v;
return *this;
}
operator string() { return this->value; }
};
list<HashItem<Key, Value>>* table;
int current_total = 0;
float FILL_LEVEL = 0.8; // Füllgrad, between 0 and 1
// not const:
int CAPACITY = 100; // default value
// for hash functions/preparing for use with strings:
const int PRIME_CONST = 31;
int hash_function(string key);
int hash_function(int key);
// std::hash?
void rehash();
public:
HashTable() {
cout << "ht cstructed, intitial_capacity is (default:) " << CAPACITY << endl;
}
HashTable(int initial_capacity) {
cout << "ht cstructed, intitial_capacity is " << initial_capacity << endl;
CAPACITY = initial_capacity;
}
//// RULE OF THREE
//// copy ctor
//HashTable(HashTable& const ht);
//// destructor
//~HashTable();
//// (copy) assignment operator
//HashTable& operator=(HashTable& const ht);
//// RULE OF FIVE
//// move ctor
//HashTable(HashTable&& ht); // && -> rvalue
//// move assignment operator
//HashTable& operator=(HashTable&& ht);
//// Hash Table operations
void put(Key key, Value value) {
// allocate memory with first put
if (current_total == 0)
table = new list<HashItem<key, value>>[CAPACITY];
HashItem<key, value>* hi = new HashItem(key, value);
int hash = hash_function(key);
if (find(table[hash].begin(), table[hash].end(), *hi) == table[hash].end()) {
// only put if not already in list
table[hash].push_back(*hi);
}
current_total++;
//cout << "current total is " << current_total << " of " << FILL_LEVEL * CAPACITY << endl;
// rehash check
if (current_total > (FILL_LEVEL * CAPACITY)) {
rehash();
//cout << "fill level reached: rehashed" << endl;
}
}
//void remove(int key, string value);
//string get(int key);
//// for part b)
//HashItem& get_item(int key) {
// int list_index = hash_function(key); // list_index = hash_code
// if (!table[list_index].empty()) {
// for (auto &list_item : table[list_index]) {
// if (key == list_item.key) {
// return list_item;
// }
// }
// }
// HashItem hi(key, "");
// return hi;
//}
//friend ostream& operator<<(ostream& os, const HashTable& ht);
//void clear();
//bool contains(int key);
//bool contains_value(string value);
//// fill levels
//void set_fill_level(float new_level);
//float get_fill_level();
//// b)
//// Overloading [] operator to access elements in array style
//HashItem& operator[] (int key) {
// if (this != nullptr)
// return this->get_item(key);
// HashItem hi(key, "");
// // stand-in hash item in case not in hash table
// return hi;
//}
};
Call in my main.cpp:
#include <iostream>
#include "HashTable.h"
using namespace std;
#define DEBUG(X) cout << (#X) << " = " << (X) << endl
HashTable<int, string> ht;
void put_test() {
cout << "--------------- put test ----------------------------------" << endl;
ht.put(10, "test");
}
int main() {
put_test();
}
Here is the class
#include <fstream>
#include <cstdlib>
#include <math.h>
#include <iomanip>
#include <iostream>
using namespace std;
class Point {
protected:
int x, y;
double operator-(const Point &def){
return sqrt(pow((x-def.x),2.0)+
pow((y-def.y),2.0));
}
};
class Circle: public Point {
private:
int radius;
public:
Circle(){
this->x=x;
this->y=y;
this->radius=radius;
}
Circle(int x, int y, int radius){
this->x=x;
this->y=y;
this->radius=radius;
}
void printCircleInfo() {
cout << x << " " << y << " " << radius << " " ;
}
This is the operator I want to be the condition in my if statement.
bool operator==(const Circle &def){
return (x==def.x) & (y==def.y) & (radius==def.radius);
}
bool doIBumpIntoAnotherCircle(Circle anotherCircle){
if (anotherCircle.radius + radius >= *this - anotherCircle )
return true;
return false;
}
};
Here is main
int main(){
int x,y,radius;
const int SIZE = 13;
Circle myCircleArry[SIZE];
myCircleArry[0] = Circle(5,3,9);
cout << endl;
myCircleArry[0].printCircleInfo(); cout << " ; ";
ifstream Lab6DataFileHandle;
Lab6DataFileHandle.open("Lab6Data.txt");
while (!Lab6DataFileHandle.eof( )) {
for (int i = 1; i < SIZE; i++) {
Lab6DataFileHandle>>x;
Lab6DataFileHandle>>y;
Lab6DataFileHandle>>radius;
myCircleArry[i] = Circle(x,y,radius);
if (myCircleArry[0].doIBumpIntoAnotherCircle(myCircleArry[i])) {
myCircleArry[i].printCircleInfo(); cout << " ; ";
Here is the If statement
if ( operator==( Circle &def))
{cout <<"*";
}
}
}
}
Lab6DataFileHandle.close();
}
How do I use the overloaded operator as the condition of the if statement? If you need any clarification just ask other wise please leave an example in your answer.
Thank you for your time.
A == needs two arguments (even if the overload is a member), you would write the if as any other if statement:
if(circle1 == circle2) { ... }
and if there's a matching overload the compiler would transform that into something like:
if(circle1.operator ==(circle2)) { ... }
For some reason, all of the functions in my program with a map as a parameter are not working. This function is the one that calls all of them (pageAndTimestamp is a struct btw):
void fifo(int framesize, int numref, int* pagestream)
{
double hit = 0, size = numref;
map<int, pageAndTimestamp> frames = frameMaker(framesize);
for (int time = 0; time < numref; time++)
{
if (pageLoaded(pagestream[time], frames))
{
hit++;
output(time, pagestream[time], size, hit, frames);
}
else
{
int loc = findPageToReplace(frames);
replacePage(loc, pagestream[time], time, frames);
output(time, pagestream[time], size, hit, frames);
}
}
}
These are the functions that are not working properly:
bool pageLoaded(int page, map<int, pageAndTimestamp> m)
{
for (const auto& it : m)
{
if (it.second.a[0] == page)
return true;
}
return false;
}
int findPageToReplace(map<int, pageAndTimestamp> m)
{
int timestamp = INT_MAX;
int replaceLoc = 0;
for (const auto& it : m)
{
if (it.second.a[1] == -1)
return it.first;
else
{
if (it.second.a[1] < timestamp)
{
timestamp = it.second.a[1];
replaceLoc = it.first;
}
}
}
return replaceLoc;
}
void replacePage(int loc, int page, int time, map<int, pageAndTimestamp> m)
{
m.at(loc).a[0] = page;
m.at(loc).a[1] = time;
}
void output(int t, int p, double s, double h, map<int, pageAndTimestamp> m)
{
cout << "Time: " << t << endl << "Page: " << p << endl;
for(const auto& it : m)
cout << "Frame" << it.first << ": " << it.second.a[0] << endl;
cout << "Hit ratio: " << h << " / " << s << " (" << h / s << ")" << endl
<< endl << endl;
}
When I run the program in the Visual Studio 2017 debugger, when I step into any of the above functions, the debugger takes me to this function header in the map standard header:
map(const map& _Right)
: _Mybase(_Right, _Alnode_traits::select_on_container_copy_construction(_Right._Getal()))
{ // construct map by copying _Right
}
I don't know what the problem is, or why the debugger is taking me to this function header. How do I fix this?
The function replacePage for example, is defined as:
void replacePage(int loc, int page, int time, map<int, pageAndTimestamp> m)
This function takes a map as a value, not a reference or pointer. Thus, when you call it as follows:
replacePage(loc, pagestream[time], time, frames);
then the map frames is copied into the variable m in your function. This is why the debugger, for example, takes you to the copy constructor for a map.
Further, it means that the replacePage code
m.at(loc).a[0] = page;
m.at(loc).a[1] = time;
is making its changes to a copy of frames, not frames itself.
You probably want functions with signatures of the form:
bool pageLoaded(int page, const map<int, pageAndTimestamp>& m)
int findPageToReplace(const map<int, pageAndTimestamp>& m)
void replacePage(int loc, int page, int time, map<int, pageAndTimestamp>& m)
void output(int t, int p, double s, double h, const map<int, pageAndTimestamp>& m)
in which most of the functions take a constant reference, while replacePage requires a (non-const) reference.
I am trying to convert struct with boolean value into an another variable of boolean type. I am trying using static_cast and reinterpet_cast.
int main()
{
bool c,d;
struct b {
bool b1 = false;
bool b2 = false;
};
c = reinterpret_cast<uint8_t*>(&b);
d = (static_cast<uint8_t*>(static_cast<void*>(&b)));
cout <<c <<endl;
cout <<d <<endl;
return 0;
}
The error is:
main.cpp:22:38: error: expected primary-expression before ')' token
c = reinterpret_cast<uint8_t*>(&b);
^
main.cpp:23:53: error: expected primary-expression before ')' token
d = (static_cast<uint8_t*>(static_cast<void*>(&b)));
You cannot convert an instance of a struct to a bool where the value is the Boolean or of all it's members with just a cast. You need to tell the compiler how to make the object a bool and you do that by overloading the operator bool for the class. In there you do the logic to tell if it should be considered true or false. That would look like
struct Foo
{
bool a = true;
bool b = true;
bool c = false;
operator bool() { return a || b || c; }
};
int main()
{
Foo f;
std::cout << static_cast<bool>(f);
}
ouput:
1
If you have a lot of members like you said you should consider using an array instead of separate members so you can write a loop instead. C++ doesn't have reflection yet so there is no easy way to tell it to or together all the members.
If you have control over the struct definition, this might be a good place to use bit-wise logic. If you have up to 128 boolean values, you could handle them them all within a couple 64-bit vars. To check an individual boolean, you'd use a mask to only check against the intended bit. And for the case described in the question, you could do a boolean-OR operation on the 64-bit vars. something like this:
struct b {
uint64_t boolset_a;
uint64_t boolset_b;
}
So if you had defined var_b to be of type struct b, you could do this to see if any of them were true: var_b.boolset_a || var_b.boolset_b
This should, I believe, be a more efficient methodology as it will not require 100+ boolean operations to see if any of them are true.
I'd not do a cast but I'd use a member function with an explicit name:
int main()
{
struct b {
bool b1 = false;
bool b2 = false;
bool b3 = false;
bool AtLeastOneIsTrue() { return b1 || b2 || b3; };
};
b str;
str.b2 = true;
cout << str.AtLeastOneIsTrue() << endl;
str.b2 = false;
cout << str.AtLeastOneIsTrue() << endl;
}
Output
1
0
But on the other hand if your struct has 100 different bool members, the AtLeastOneIsTrue function would be terrible. An array of bool or a vector of bool would be more appropriate then.
Sample using a vector:
#include <iostream>
#include <vector>
using namespace std;
int main()
{
struct b {
vector<bool> values;
b(int numberofbools) { values.assign(numberofbools, false); }; // constructor
bool AtLeastOneIsTrue()
{
for (bool v : values)
{
if (v)
return true;
}
return false;
};
void Set(int number, bool value)
{
values[number] = value;
}
};
b str(100); // str has 100 bool values, all false
cout << str.AtLeastOneIsTrue() << endl; // print1 0
str.Set(3, true); // set value number 3 to true
cout << str.AtLeastOneIsTrue() << endl; // prints 1
}
IMHO, your better create a member function or an operator for the struct, like shown by NathanOliver, that operates on the booleans in there. In fact, your could create at least two member functions, one that tells you whether any of the booleans is true, and other that tells you if all are true.
My approach, as this will probably need to be extendable in some sense in a normal project in the future, is to use a vector of booleans, or better a map, so that each boolean can be given a name, and then two functions (methods if they belong to a bigger class, like a configuration entity) that provide the all/any computation on those flags.
A quick and dirty example of this approach is shown below (compile with C++11 activated, for the auto loop, or modify otherwise):
#include <iostream>
#include <string>
#include <map>
using namespace std;
typedef map<string, bool> Flags;
bool allOK(Flags & fl) {
bool result = true;
for (auto & kv : fl) { result &= kv.second; }
return result;
}
bool anyOK(Flags & fl) {
bool result = false;
for (auto & kv : fl) { result |= kv.second; }
return result;
}
int main(int argc, char * arg[])
{
Flags flags;
flags["a"] = true;
flags["b"] = true;
flags["the_third_flag"] = false;
cout << "1. ALL OK: " << boolalpha << allOK(flags)
<< " - ANY OK: " << anyOK(flags) << '\n';
flags["the_third_flag"] = true;
cout << "2. ALL OK: " << boolalpha << allOK(flags)
<< " - ANY OK: " << anyOK(flags) << '\n';
flags["a"] = false;
flags["b"] = false;
flags["the_third_flag"] = false;
flags["a_last_flag"] = false;
cout << "3. ALL OK: " << boolalpha << allOK(flags)
<< " - ANY OK: " << anyOK(flags) << '\n';
return 0;
}
I have a problem when accessing the overflowed square bracket in a public method of my class. Here is the code:
#include <iostream>
#include <cassert>
#include <cmath>
using namespace std;
template<unsigned int DIM> class Vector
{
private:
double mData[DIM];
public:
Vector(double tableau[DIM])
{
for(int i=0; i<DIM; i++)
{
mData[i] = tableau[i];
}
}
double operator[](int index)
{
assert(index < DIM);
assert(index > -1);
assert(-pow(10,-6)<=mData[index]<=1+pow(10,-6));
if(mData[index]>=0 && mData[index]<=1)
{
return mData[index];
}
else if(mData[index]<0 && mData[index]>=pow(10,-6))
{
return 0.0;
}
else if(mData[index]>1 && mData[index]<= 1+ pow(10,-6))
{
return 1.0;
}
}
double getDim() const
{
return DIM;
}
void print() const
{
for(int i=0;i<getDim();i++)
{
cout << this[i] << " "; //PROBLEM!!
}
}
};
int main()
{
double err=pow(10,-6);
double tableau[5];
tableau[0] = 0.5;
tableau[1] = 0.79;
tableau[2] = err;
tableau[3] = 1+err;
tableau[4] = 0;
Vector<5> proba(tableau);
proba.print();
}
I have tried with *this, this->, but anything appeared to work.
I hope you could help me.
Florent
Member operator overloads require a value or reference of the class type, and this is a pointer. So you either need to dereference the this pointer prior to using the operator, like this:
(*this)[i]
Or you can call the operator directly, which has the advantage of being totally explicit in its intent, but has the disadvantage of being a bit wordy and a bit more obscure (and therefore more likely to trip up anyone who reads it):
this->operator[](i)
If you have already tried *this[i] and found that it doesn't fix the problem, that's because it actually means *(this[i])!
Apart from wrong implementation of operator[], there is wrong use of it:-
cout << this[i] << " ";
This should be
cout << (*this)[i] << " "; //is you want to implement that way...
this is just a pointer, so to access operator[] you can either dereference it first:
cout << (*this)[i] << " ";
Or call the function directly (not preferred):
cout << this->operator[](i) << " ";