This does not work. It gives an error regarding ISO C++ forbidding initialization.
class hash_map
{
private:
hash_entry **table;
const int TABLE_SIZE = 128;
public:
hash_map()
{
table = new hash_entry*[TABLE_SIZE];
for (int i = 0; i < TABLE_SIZE; i++)
table[i] = NULL;
}
int get(int key)
{
int hash = (key % TABLE_SIZE);
while (table[hash] != NULL && table[hash]->getKey() != key)
hash = (hash + 1) % TABLE_SIZE;
if (table[hash] == NULL)
return -1;
else
return table[hash]->getValue();
}
void put(int key, int value)
{
int hash = (key % TABLE_SIZE);
while (table[hash] != NULL && table[hash]->getKey() != key)
hash = (hash + 1) % TABLE_SIZE;
if (table[hash] != NULL)
delete table[hash];
table[hash] = new hash_entry(key, value);
}
~hash_map()
{
for (int i = 0; i < TABLE_SIZE; i++)
if (table[i] != NULL) delete table[i];
delete[] table;
}
};
const int TABLE_SIZE = 128;
This is the cause of the compilation error. It is allowed in C++11 only, not in C++03 and C++98.
Either make it a static member of the class, OR initialize it in the constructor. Make use of member-initialization-list for it.
Apart from that dont forget to implement copy-semantics following Rule of Three, OR disable it altogether by declaring them (don't define them) in the private section. I think, disabling it would make more sense in this case.
You need to initialize it in constructor, change
const int TABLE_SIZE = 128;
to
const int TABLE_SIZE;
and the constructor from
hash_map()
{
table = new hash_entry*[TABLE_SIZE];
for (int i = 0; i < TABLE_SIZE; i++) table[i] = NULL;
}
to
hash_map() : TABLE_SIZE(128)
{
table = new hash_entry*[TABLE_SIZE];
for (int i = 0; i < TABLE_SIZE; i++) table[i] = NULL;
}
You need to put the initialization into the constructor like this:
class hash_map
{
private:
hash_entry **table;
const int TABLE_SIZE;
public:
hash_map(): TABLE_SIZE(128)
{
table = new hash_entry*[TABLE_SIZE];
for (int i = 0; i < TABLE_SIZE; i++) table[i] = NULL;
}
...
You could have been more specific and provide a minimal example that reproduces the problem and an exact error that compiler gives you. But anyway, even without a psychic mode turned on, it is obvious that error in on this line:
const int TABLE_SIZE = 128;
You cannot initialize a class member like that, it has to be done in constructor initialization list, unless this member is a static constant compile-time expression (constexpr in C++11).
So remove = 128 from that line and modify constructor to do this:
hash_map() : TABLE_SIZE (128)
{
....
Use enumerated type:
class hash_map
{
private:
enum
{
TABLE_SIZE = 128;
};
hash_entry * table[TABLE_SIZE];
//...
};
Related
I have a class that has 2 bools and an array of pointers which I allocate on heap.The problem is when it calls the destructor it gives me an error,probably because it deletes too much,I saw it trying to access 0xdddddd and showing me this "Exception thrown: read access violation.
this was 0xDEEEDEEF."
1.How do I use "delete" better,is it because of the operator overload?
2.Also it says that i didn't initialized "QuadTree::childs",why?
class QuadTree {
public:
QuadTree* childs[4];
bool info;
bool parent;
QuadTree() {
for (int i = 0; i < 4; ++i) {
childs[i]=NULL;
}
info = false;
parent = false;
}
~QuadTree() {
for (int i = 0; i < 4; ++i) {
delete childs[i];
}
}
QuadTree& operator=(const QuadTree& tree) {
for (int i = 0; i < 4; ++i) {
childs[i] = new QuadTree;
if (tree.childs[i]->parent == 1) {
childs[i] = tree.childs[i];
}
childs[i]->info = tree.childs[i]->info;
childs[i]->parent = tree.childs[i]->parent;
}
return *this;
}
}
So this is the code for adding two trees.I created the overload operator for the next reason,if the node of one tree is white and the other is a parent,i just want to copy the parent.
void addTrees(const QuadTree& tree1, const QuadTree& tree2, QuadTree& end) {
if (tree1.info == 1 || tree2.info == 1) {
end.info = 1;
return;
}
else if (tree1.parent == 1 && tree2.parent == 1) {
end.parent = 1;
for (int i = 0; i < 4; ++i) {
end.childs[i] = new QuadTree;
addTrees(*tree1.childs[i], *tree2.childs[i], *end.childs[i]);
}
}
else if (tree1.parent == 1) {
end.parent = 1;
end = tree1;
}
else if (tree2.parent == 1) {
end.parent = 1;
end = tree2;
}
else {
end.info = 0;
}
}
The line childs[i] = tree.childs[i]; is not doing what you think it is doing.
You are now referencing the memory that they allocated and no longer referencing the memory that you allocated. Whoever tries to delete this memory second will have a bad time.
If you want to copy their child into your recently allocated child you will need to dereference the pointer to operate on the object itself. *childs[i] = *tree.childs[i]
The problem is in your assigmnent operator.
QuadTree& operator=(const QuadTree& tree) {
for (int i = 0; i < 4; ++i) {
childs[i] = new QuadTree;
if (tree.childs[i]->parent == 1) {
childs[i] = tree.childs[i];
}
childs[i]->info = tree.childs[i]->info;
childs[i]->parent = tree.childs[i]->parent;
}
return *this;
}
};
In these lines:
if (tree.childs[i]->parent == 1) {
childs[i]->info = tree.childs[i]->info;
childs[i]->parent = tree.childs[i]->parent;
childs[i] maybe a nullptr which is ok for assignment but not ok for dereferencing.
And with ->parent you do derefence a nullptr
Please check for nullptr before derefencing.
The code below a solution to the following requirement:
"Change the representation of Link and List from ยง27.9 without changing the user interface provided by the functions. Allocate Links in an array of Links and have the members: first, last, prev, and next be ints (indices into the array). " - Exercise 6 Chapter 27 - Programming: Principles and Practice Using C++ B. Stroustrup
The interface is inherited from an ordinary implementation of an Intrusive doubly linked list. I've added the bool array (and the associated functions) to keep track of memory:
#include <iostream>
struct Link
{
int next;
int prev;
};
//------------------------------------------------------------------------------------
struct List
{
Link** head;
int first; // points to the current first node
int last;
bool* available;
int list_size;
int get_index()
{
for (int i = 0; i < list_size; ++i)
{
if (available[i] == true)
{
available[i] = false;
return i;
}
}
throw std::bad_alloc("bla bla!\n");
}
List()
{
list_size = 30;
head = new Link*[list_size];
available = new bool[list_size];
first = -1;
last = -1;
for (int i = 0; i < list_size; ++i)
{
available[i] = true;
}
}
void List::push_back(Link* l)
{
if (l == nullptr)
{
throw std::invalid_argument("bla bla!\n");
}
int index = get_index();
head[index] = l;
if (last != -1)
{
head[last]->next = index;
head[index]->prev = last;
}
else
{
first = index;
head[index]->prev = -1;
}
last = index;
head[index]->next = -1;
}
void push_front(Link* l)
{
if (l == nullptr)
{
throw std::invalid_argument("bla bla\n");
}
int index = get_index();
head[index] = l;
if (first != -1)
{
head[first]->prev = index;
head[index]->next = first;
}
else
{
last = index;
head[index]->next = -1;
}
first = index;
head[index]->prev = -1;
}
// index = ptr - base
std::ptrdiff_t index_from_address(Link* l) { return l - head[0]; }
Link* front() const { return head[first]; }
};
//------------------------------------------------------------------------------------
int main()
{
List l;
for (int i = 0; i < 10; ++i)
{
l.push_back(new Link());
}
for (int i = 0; i < 10; ++i)
{
l.push_front(new Link());
}
std::cout <<"first = "<< l.first <<", index = " << l.index_from_address(l.front());
getchar();
}
Expected result:
first = 19, index = 19
Actual result:
first = 19, index = 194
Why?
l - head[0]
Here you compare the values of the two pointers. You let all pointers in the array be default initialized, so their values are indeterminate, and therefore the behaviour of accessing the values is undefined.
You probably intended index_from_address to find the index where a particular pointer object is stored - rather than the object that is pointed to, since the pointed to object is not in the array pointed by head. To do that, you must add a whole bunch of &:
Link*& front() const // return a reference to the pointer object, not a copy
// take a reference to the pointer as an argument, add const for good measure
std::ptrdiff_t index_from_address(Link*& l) const
// compare the addresses of the pointers, rather than values
{ return &l - &head[0]; }
I am trying for write a hash map, but the constructor won't allocate memory, can someone help me out, I am new to code, sorry for bother you guys, but I will be really appreciated for your help.
class HashMap {
private:
HashEntry **table;
int count;
int TABLE_SIZE;
public:
HashMap()
{
TABLE_SIZE = 128;
table = new HashEntry*[TABLE_SIZE];
for (int i = 0; i < TABLE_SIZE; i++)
table[i] = NULL;
count=0;
}
}
class HashEntry
{
private:
int key;
int value;
public:
HashEntry(){}
~HashEntry(){}
HashEntry(int key, int value) {
this->key = key;
this->value = value;
}
int getKey() {
return key;
}
int getValue() {
return value;
}
void setValue(int value) {
this->value = value;
}
};
When it runs,
table = new HashEntry*[TABLE_SIZE];
the table was unable to read memory, I am newbie in coding, plz give me some help, thanks!
You could create an array of your objects via malloc(), which allows you to allocate memory dynamically. I could not test this code yet, but it should work the way it is:
HashEntry* table;
int TABLE_SIZE;
HashMap(){
TABLE_SIZE = 128;
table = (HashEntry*)malloc(sizeof(HashEntry) * TABLE_SIZE);
for(int i = 0; i < TABLE_SIZE; i++){
table[i] = NULL; //If you want to create your objects, you need to replace `NULL` with `new HashEntry()`
}
}
I have to create a very BASIC hash map of Functions pointers. My requirement is just add values in it and then get it based on key. For some political reason, I can not use any standard librabry. I have a code which works fine. But if I want a functions pointers to my CLASS MEMBER FUNCTIONS then this do not work. Any suggestion what should be the modification in below code.
In this PING and REFRESH are independent functions. So this code works. But if I move these functions to HashMap class then it fails.
Code:--
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <iomanip>
using namespace std;
typedef void (*FunctionPtr)();
void ping(){
cout<<"ping";
}
void refresh(){
cout<<"refresh";
}
class HashEntry {
private:
int key;
FunctionPtr func_ptr1;;
public:
HashEntry(int key, FunctionPtr fptr) {
this->key = key;
this->func_ptr1 = fptr;
}
int getKey() {
return key;
}
FunctionPtr getValue() {
return this->func_ptr1;
}
};
const int TABLE_SIZE = 128;
class HashMap {
private:
HashEntry **table;
public:
HashMap() {
table = new HashEntry*[TABLE_SIZE];
for (int i = 0; i < TABLE_SIZE; i++)
table[i] = NULL;
}
FunctionPtr get(int key) {
int hash = (key % TABLE_SIZE);
while (table[hash] != NULL && table[hash]->getKey() != key)
hash = (hash + 1) % TABLE_SIZE;
if (table[hash] == NULL)
return NULL;
else
return table[hash]->getValue();
}
void put(int key, FunctionPtr fptr) {
int hash = (key % TABLE_SIZE);
while (table[hash] != NULL && table[hash]->getKey() != key)
hash = (hash + 1) % TABLE_SIZE;
if (table[hash] != NULL)
delete table[hash];
table[hash] = new HashEntry(key, fptr);
}
~HashMap() {
for (int i = 0; i < TABLE_SIZE; i++)
if (table[i] != NULL)
delete table[i];
delete[] table;
}
};
void main(){
HashMap* pHashsMap = new HashMap();
pHashsMap->put(1,ping);
pHashsMap->put(2,refresh);
pHashsMap->put(3,ping);
pHashsMap->put(4,refresh);
pHashsMap->put(5,ping);
pHashsMap->put(6,refresh);
cout<<" Key 1---"<<pHashsMap->get(1)<<endl;
pHashsMap->get(1)();
cout<<" Key 5---"<<pHashsMap->get(5)<<endl;
pHashsMap->get(5)();
cout<<" Key 3---"<<pHashsMap->get(3)<<endl;
pHashsMap->get(3)();
cout<<" Key 6---"<<pHashsMap->get(6)<<endl;
pHashsMap->get(6)();
delete pHashsMap;
}
The smart-alec answer: inspect the code for std::bind, learn from it, and create your own (though tbh, not using STL/boost isn't smart...).
the simpler answer: you need to create a union type to hold your normal function pointer and a class member function pointer, then store a bool to indicate if it is a class pointer:
class funcbind_t
{
union
{
void (*pf)();
void (SomeClass::*mfp)();
};
bool member;
funcbind_t(void (*_pf)()) : pf(_pf), member(false)
{
}
funcbind_t(void (SomeClass::*_mpf)()) : mpf(_mpf), member(true)
{
}
void operator ()()
{
if(member)
mfp();
else
fp();
}
};
as you can see, this is going to get messy when you start needing differing parameters to the functions.
Alright, so without going into detail on why I'm writing this class, here it is.
template<class aType>
class nArray
{
public:
aType& operator[](int i)
{
return Array[i];
}
nArray()
{
aType * Array = new aType[0];
_Size = 0;
_MaxSize = 0;
_Count = 0;
}
nArray(int Count)
{
aType * Array = new aType[Count*2]();
_Size = Count;
_MaxSize = Count * 2;
_Count = 0;
}
int Resize(int newSize)
{
aType *temp = new aType[newSize*2];
for(int i=0;i<_Count;i++)
{
temp[i] = Array[i];
}
delete[] Array;
aType * Array = new aType[newSize*2];
for(int i=0;i<_Count;i++)
{
Array[i] = temp[i];
}
delete [] temp;
_Size = newSize;
_MaxSize = newSize*2;
return 0;
}
int Push_Back(aType Item)
{
if(_Count+1 >= _Size)
{
Resize(_MaxSize);
}
Array[_Count] = Item;
_Count++;
return _Count - 1;
}
aType GetAt(int Index, int &ret)
{
if(Index > _Size-1)
ret = 1;
return aType();
ret = 0;
return Array[Index];
}
private:
int _Size;
int _Count;
int _MaxSize;
aType * Array;
};
It is supposed to be a std::Vector type object, without all the bells and whistles.
Problem is, it doesn't seem to work.
I basically start by going
nArray<string> ca = nArray<string>(5);
ca.Push_Back("asdf");
ca.Push_Back("asdf2");
int intret = 0;
cout << ca.GetAt(1,intret);
I get an Access Violation Reading Location error and it hits on the line
Array[_Count] = Item
in the Push_back function.
The problem seems to be that it's not treating the Array object as an array in memory.
I've spent time going through the code step by step, and I don't know what else to say, it's not operating right. I don't know how to word it right. I'm just hoping someone will read my code and point out a stupid mistake I've made, because I'm sure that's all it amounts to.
Update
So now I changed 3 initializations of Array in nArray(), nArray(int Count), and Resize(int newSize)
template<class aType>
class nArray
{
public:
aType& operator[](int i)
{
return Array[i];
}
nArray()
{
Array = new aType[0];
_Size = 0;
_MaxSize = 0;
_Count = 0;
}
nArray(int Count)
{
Array = new aType[Count*2]();
_Size = Count;
_MaxSize = Count * 2;
_Count = 0;
}
int Resize(int newSize)
{
aType *temp = new aType[newSize*2];
for(int i=0;i<_Count;i++)
{
temp[i] = Array[i];
}
delete[] Array;
Array = new aType[newSize*2];
for(int i=0;i<_Count;i++)
{
Array[i] = temp[i];
}
delete [] temp;
_Size = newSize;
_MaxSize = newSize*2;
return 0;
}
int Push_Back(aType Item)
{
if(_Count+1 >= _Size)
{
Resize(_MaxSize);
}
Array[_Count] = Item;
_Count++;
return _Count - 1;
}
aType GetAt(int Index, int &ret)
{
if(Index > _Size-1)
ret = 1;
return aType();
ret = 0;
return Array[Index];
}
private:
int _Size;
int _Count;
int _MaxSize;
aType * Array;
};
This is how my code was before. Anyway, the original problem was the fact that when I try to access a specific element in the array, it just accesses the first element, and it doesn't seem to add elements eather. It doesn't seem to be treating Array as an array.
int Resize(int newSize)
{
.
.
aType * Array = new aType[newSize*2];
At this point, instead of updating the member variable as you intended, you've actually created a local variable called Array whose value is discarded when you exit from Resize(). Change the line to
Array = new aType[newSize*2];
The same thing is happening in your constructors, they also need changing accordingly. Moreover, since the default constructor allocates an array, you should set the size members accordingly. You have too many of these: an array needs to keep track of current element count and maximum capacity, however you appear to have three members. What is the purpose of the third? Redundant information is bad, it makes code difficult to read and without a single point of truth it is easier to make mistakes.
With the code in Resize(), you can do better: the second copy is completely redundant.
int Resize(int newSize)
{
aType *temp = new aType[newSize*2];
for(int i=0;i<_Count;i++)
{
temp[i] = Array[i];
}
delete[] Array;
Array = temp;
_Size = newSize;
_MaxSize = newSize*2;
return 0;
}
Also, in
aType GetAt(int Index, int &ret)
{
if(Index > _Size-1)
ret = 1;
return aType();
ret = 0;
return Array[Index];
}
you need curly braces around body of the if(), just indentation on its own won't do the trick:
aType GetAt(int Index, int &ret)
{
if(Index > _Size-1)
{
ret = 1;
return aType();
}
ret = 0;
return Array[Index];
}
You have a number of problems. At a guess, the one causing problems so far is that your default ctor (nArray::nArray()) defines a local variable named Array that it initializes, which leaves nArray::Array uninitialized.
Though you probably haven't seen any symptoms from it (yet), you do have at least one more problem. Names starting with an underscore followed by a capital letter (such as your _Size, _MaxSize, and _Count) are reserved for the implementation -- i.e., you're not allowed to use them.
The logic in your Resize also looks needlessly inefficient (if not outright broken), though given the time maybe it's just my brain not working quite right at this hour of the morning.
Your array is not initialized by the constructors and resize function (working on local vars instead).
And is there a reason you want to store instances of string and not pointers to string (string *) ?
I think the answer after the changes is in moonshadow's reply:
aType GetAt(int Index, int &ret)
{
if(Index > _Size-1)
ret = 1;
return aType();
ret = 0;
return Array[Index];
}
This code will always return aType(), the last two lines will never be reached.
You might also want to check what happens if you start out with a default-constructed nArray. (Hint: you call Resize(_MaxSize); but what is the value of _MaxSize in this case?
Edit:
This outputs "asdf2" for me as it should be (with the initialization and the braces fixed):
template<class aType>
class nArray
{
public:
aType& operator[](int i)
{
return Array[i];
}
nArray()
{
Array = new aType[0];
_Size = 0;
_MaxSize = 0;
_Count = 0;
}
nArray(int Count)
{
Array = new aType[Count*2]();
_Size = Count;
_MaxSize = Count * 2;
_Count = 0;
}
int Resize(int newSize)
{
aType *temp = new aType[newSize*2];
for(int i=0;i<_Count;i++)
{
temp[i] = Array[i];
}
delete[] Array;
Array = new aType[newSize*2];
for(int i=0;i<_Count;i++)
{
Array[i] = temp[i];
}
delete [] temp;
_Size = newSize;
_MaxSize = newSize*2;
return 0;
}
int Push_Back(aType Item)
{
if(_Count+1 >= _Size)
{
Resize(_MaxSize);
}
Array[_Count] = Item;
_Count++;
return _Count - 1;
}
aType GetAt(int Index, int &ret)
{
if(Index > _Size-1) {
ret = 1;
return aType();
}
ret = 0;
return Array[Index];
}
private:
int _Size;
int _Count;
int _MaxSize;
aType * Array;
};
#include <string>
#include <iostream>
using namespace std;
int main()
{
nArray<string> ca = nArray<string>(5);
ca.Push_Back("asdf");
ca.Push_Back("asdf2");
int intret = 0;
cout << ca.GetAt(1,intret);
}