Reputation: 165
For a research project I'm working on a computer model. Upto now I've gotten away with not understanding c++ very well, because the tasks it did were not very complicated. However I now need a fast hash table so I'm trying to integrate the Google Sparse Hash. After two days of tinkering with header files I'm stuck.
Somehow the entire hash table gets emptied as soon as the constructor of my object is finished. I hope you can help me to fix the following code. I excluded all the code that I'm sure is irrelevant, but let me know if I need to add more.
Makefile:
# Object files:
OBJ = traverse-markov.o gene.o genome.o markovgraph.o
# Header files:
HDR = gene.h header.h genome.h markovgraph.h
# Libraries that we need to link to:
#LIBS = -lGL -lX11 -lm
# One rule to invoke what we need:
all : traverse-markov
# C++ 'compile' command:
CPP = g++ -ggdb3
LINK= g++
# Generic rules
%.o : %.cc ${HDRS}
${CPP} -o $@ -I ~/lib/ -c $<
# The final step:
traverse-markov : ${OBJ}
${LINK} -o $@ ${LIBS} ${OBJ}
clean:
rm -rf *.o traverse-markov
header.h:
#ifndef HEADER_H
#define HEADER_H
//#include <stdint.h>
#include <iostream>
#include <vector>
#include <ctime>
#include <fstream>
#include <boost/random.hpp>
#include <sparsehash/dense_hash_map>
#include "gene.h"
#include "genome.h"
#include "markovgraph.h"
//Setting up the randomness
typedef boost::mt19937 RandomNumberGenerator;
typedef boost::uniform_int<> NumberDistribution;
typedef boost::variate_generator<RandomNumberGenerator&, NumberDistribution> Generator;
static RandomNumberGenerator generator;
#endif
traverse-markov.cc:
#include "header.h"
int main (int argc, char* argv[]) {
Markovgraph markov;
markov.add_vertex("a");
return 0;
}
markovgraph.h:
#ifndef MARKOVGRAPH_H
#define MARKOVGRAPH_H
extern uint64_t MurmurHash64A ( const void * key, int len, unsigned int seed );
// simple hash adapter for types without pointers
template<typename T>
struct MurmurHasher {
size_t operator()(const T& t) const {
return MurmurHash64A(&t, sizeof(t), 0);
}
};
// specialization for strings
template<>
struct MurmurHasher<std::string> {
size_t operator()(const std::string& t) const {
return MurmurHash64A(t.c_str(), t.size(), 0);
}
};
struct eqstr
{
bool operator()(const char* s1, const char* s2) const
{
return (s1 == s2) || (s1 && s2 && strcmp(s1, s2) == 0);
}
};
class Markovgraph {
//Private variables
google::dense_hash_map<const char*, long, MurmurHasher<const char*>, eqstr> vertices;
google::dense_hash_map<const char*, long, MurmurHasher<const char*>, eqstr> edges;
public:
//Public variables
//Functions
Markovgraph(); //Constructor
void add_vertex(std::string vertex);
//add_edge(std::string upvertex,std::string downvertex);
~Markovgraph(); //Destructor
};
#endif
markovgraph.cc:
//Include the header
#include "header.h"
// 64-bit hash for 64-bit platforms
// copied from https://sites.google.com/site/murmurhash/
uint64_t MurmurHash64A ( const void * key, int len, unsigned int seed ) {
const uint64_t m = 0xc6a4a7935bd1e995;
const int r = 47;
uint64_t h = seed ^ (len * m);
const uint64_t * data = (const uint64_t *)key;
const uint64_t * end = data + (len/8);
while(data != end)
{
uint64_t k = *data++;
k *= m;
k ^= k >> r;
k *= m;
h ^= k;
h *= m;
}
const unsigned char * data2 = (const unsigned char*)data;
switch(len & 7)
{
case 7: h ^= uint64_t(data2[6]) << 48;
case 6: h ^= uint64_t(data2[5]) << 40;
case 5: h ^= uint64_t(data2[4]) << 32;
case 4: h ^= uint64_t(data2[3]) << 24;
case 3: h ^= uint64_t(data2[2]) << 16;
case 2: h ^= uint64_t(data2[1]) << 8;
case 1: h ^= uint64_t(data2[0]);
h *= m;
};
h ^= h >> r;
h *= m;
h ^= h >> r;
return h;
}
//Constructor
Markovgraph::Markovgraph() {
google::dense_hash_map<const char*, long, MurmurHasher<const char*>, eqstr> vertices;
vertices.set_empty_key(NULL);
google::dense_hash_map<const char*, long, MurmurHasher<const char*>, eqstr> edges;
edges.set_empty_key(NULL);
vertices["a"] = 10000;
vertices["b"] = 573;
std::cout << vertices["a"] << std::endl;
std::cout << vertices["b"] << std::endl;
std::cout << vertices.size() << std::endl;
}
//Add vertex function
void Markovgraph::add_vertex(std::string vertex) {
std::cout << vertices.size() << std::endl;
}
//Destructor
Markovgraph::~Markovgraph() {
//Destroy things...
}
Right now this outputs:
10000
573
2
0
So the first three numbers a according to my expectations. But the as soon as the Markovgraph::add_vertex
function is called (or as soon as the constructor is done) the entire vertices hash is empty again.
EDIT
Ok, removing the variables edges and vertices from the constructor did the trick. However now something else goes wrong:
//Constructor
Markovgraph::Markovgraph() {
vertices.set_empty_key(NULL);
edges.set_empty_key(NULL);
}
//Add vertex function
void Markovgraph::add_vertex(std::string vertex) {
vertices[vertex] = 1;
std::cout << vertices[vertex] << std::endl;
}
Now I'm getting the following error when compiling:
markovgraph.cc:58: error: no match for ‘operator[]’ in ‘((Markovgraph*)this)->Markovgraph::vertices[vertextoadd]’
.
Upvotes: 0
Views: 1266
Reputation: 249394
Here, in your constructor:
google::dense_hash_map<const char*, long, MurmurHasher<const char*>, eqstr> vertices;
You have defined a new variable called vertices, which has the scope and lifetime of the constructor. You need to just remove this line, because an identical variable already exists as a member of the class. What you have done is called "shadowing", and your compiler should warn you about it if you use suitable options like -Wall
.
Upvotes: 1
Reputation: 363717
vertices
and edges
are local variables in your constructor, shadowing the instance variables of the same name. To initialize the instance variables to empty hash tables, just remove those variables from your constructor:
Markovgraph::Markovgraph() {
// note: no declarations of vertices and edges here
vertices.set_empty_key(NULL);
edges.set_empty_key(NULL);
vertices["a"] = 10000;
vertices["b"] = 573;
std::cout << vertices["a"] << std::endl;
std::cout << vertices["b"] << std::endl;
std::cout << vertices.size() << std::endl;
}
This works because the constructor implicitly calls the default constructor for the instance variables.
Upvotes: 2