Implement hash-table in C++ - c++

The following is the implementation of hashtable using C++. Can you please help me to understand what HashEntry **table is? Why it is declared as a double pointer? Is it a array and each value of the array is HashEntry?
class HashEntry {
private:
int key;
int value;
public:
HashEntry(int key, int value) {
this->key = key;
this->value = value;
}
int getKey() {
return key;
}
int getValue() {
return value;
}
};
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;
}
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 HashEntry(key, value);
}
~HashMap() {
for (int i = 0; i < TABLE_SIZE; i++)
if (table[i] != NULL)
delete table[i];
delete[] table;
}
};

In this code, table is a pointer to a pointer to HashEntry
HashEntry **table;
The general rule is to start with the variable name and the basic type, go right as much as possible then go left, see this excellent description
http://unixwiz.net/techtips/reading-cdecl.html
So you start with the variable, table, and the basic type, HashEntry which is furthest to the left. Note that the article describes the rules for 'C' where a basic type can be a struct, think of your C++ class HashEntry as a 'C' struct.
table is ... HashEntry
There is nothing else to the right of table in the declaration, so go left, and you have "*" which stands for pointer to:
table is pointer to ... HashEntry
Again you must go left in the declaration and consume the next "*", you now have
table is pointer to pointer to HashEntry
... and you are done.
It is perhaps unfortunate that table was declared that way, because table implies array, and it is not declared as an array. It turns out that in C++, as in C, an array "decays" into a pointer when it is passed to a function. Here "decays" means you have lost information, namely the size of the array.
An equivalent declaration, which I think would give the reader more insight would be:
HashEntry * table[];
Using the rules about how to interpret variable declarations, this should be read as
table is undimensioned array of pointer to HashEntry
This is equivalent from the compiler's point of view to the previous declaration, because an undimensioned array is passed as a pointer to the type of the elements of the array (the value being the address of the first element, at offset 0). A "dimensioned array" also decays to a pointer, with the loss of the dimension information. See this SO answer for more information on decaying of arrays to pointers.
What is array decaying?

Related

Resizing and copying elements in a Hashtable Array

Right now I have struct IndexLocation that defines a page number pageNum and a word number wordNum on a page, and a struct IndexRecord that consists of a specific word and its locations that is a vector of IndexLocations.
In IndexRecord.h:
struct IndexLocation {
int pageNum; //1 = first page
int wordNum; //1 = first word on page
IndexLocation(int pageNumber, int wordNumber);
};
struct IndexRecord {
//indexed word
std::string word;
//list of locations it appears
std::vector<IndexLocation> locations;
IndexRecord();
//Constructor - make a new index record with no locations
explicit IndexRecord(const std::string& wordVal);
//Add an IndexLocation to the record
// Does NOT check for duplicate records
void addLocation(const IndexLocation& loc);
//Returns true if the record contains the indicated location
bool hasLocation(const IndexLocation& loc) const;
};
Then, I have a Hash Map IndexMap which stores values of IndexRecords using the word as the key. Within one, an IndexRecord may be stored at bucket 3, have a word apple, and have locations be 1,2 and 2,5.
#include "IndexRecord.h"
class IndexMap
{
private:
int numBuckets;
int keyCount;
IndexRecord* buckets;
//handle resizing the hash table into a new array with twice as many buckets
void grow();
//Get the location this key should be placed at.
// Will either containt IndexRecord with that key or an empty IndexRecord
unsigned int getLocationFor(const std::string& key) const;
public:
//Construct HashMap with given number of buckets
IndexMap(int startingBuckets = 10);
//Destructor
~IndexMap();
//Copy constructor and assignment operators
IndexMap(const IndexMap &other);
IndexMap& operator=(const IndexMap& other);
//Returns true of indicated key is in the map
bool contains(const std::string& key) const;
//Add indicated location to the map.
// If the key does not exist in the map, add an IndexRecord for it
// If the key does exist, add a Location to its IndexRecord
void add(const std::string& key, int pageNumber, int wordNumber);
void IndexMap::add2(const std::string &key, IndexLocation location)
};
Furthermore, in IndexMap.cpp, I have the add function, the add2 function, and grow function.
void IndexMap::add(const std::string &key, int pageNumber, int wordNumber) {
if (keyCount == numBuckets)
grow();
int bucketNumber = getLocationFor(key);
if (this->contains(key) == true)
buckets[bucketNumber].addLocation(IndexLocation(pageNumber, wordNumber));
else if (this->contains(key) == false) {
while (buckets[bucketNumber].word != "?") {
if (bucketNumber < numBuckets)
bucketNumber++;
else if (bucketNumber == numBuckets)
bucketNumber = 0;
}
string foo = key;
buckets[bucketNumber].word = key;
buckets[bucketNumber].addLocation(IndexLocation(pageNumber, wordNumber));
keyCount++;
}
return;
}
void IndexMap::add2(const std::string &key, IndexLocation location) {
if (keyCount > 0.7 * numBuckets)
grow();
int bucketNumber = getLocationFor(key);
if (this->contains(key) == true)
buckets[bucketNumber].addLocation(location);
else if (this->contains(key) == false) {
while (buckets[bucketNumber].word != "?") {
if (bucketNumber < numBuckets)
bucketNumber++;
else if (bucketNumber == numBuckets)
bucketNumber = 0;
}
string foo = key;
buckets[bucketNumber].word = key;
buckets[bucketNumber].addLocation(location);
keyCount++;
}
return;
}
void IndexMap::grow() {
IndexRecord* oldTable = buckets;
int oldSize = numBuckets;
numBuckets = numBuckets * 2 + 1;
IndexRecord* newArray = new IndexRecord[numBuckets];
keyCount = 0;
for (int i = 0; i < oldSize; i++) {
if (oldTable[i].word != "?") {
this->add2(oldTable[i].word, oldTable[i].locations[i]); // having trouble here
}
}
buckets = newArray;
delete [] oldTable;
}
My issue begins here. I believe my basic logic is sound: keep the old array around with a pointer, make a new, larger one and reset the size of the HashTable, iterate through the old array and add anything it contains back into the hashtable with the add function, and then delete the old array, but this just results in a segmentation fault (SIGSEGV) once keyCount hits numBuckets. (The reason I have an add2 function which is almost identical to my add function and use it in grow is because I didn't know how to modify get a pageNumber and a wordNumber for the this->add2 line within grow; the assignment specifications say we cannot modify the original add function's header).
You never assign to buckets in grow, so the newly enlarged array is not accessible by your other functions.

hash map no viable overloaded '='

public:
typedef ics::pair<KEY,T> Entry;
typedef int (*hashfunc) (const KEY& a);
private:
int (*hash)(const KEY& k); //Hashing function used (from template or constructor)
enum bin_state {bs_empty, bs_occupied, bs_was_occupied};
Entry* map = nullptr; //Entry array
bin_state* state = nullptr; //bin_state[] describes the state of map[i]
double load_threshold; //used/bins <= load_threshold
int bins = 1; //# bins in array (should start at 1 so hash_compress doesn't % 0)
int used = 0; //Cache for number of key->value pairs in the hash table
int mod_count = 0; //For sensing concurrent modification
//Helper methods
int hash_compress (const KEY& key) const; //hash function ranged to [0,bins-1]
int find_key (const KEY& key) const; //Returns index to key's bin or -1
int next_unoccupied (int bin) const; //this bin or next beyond that is unoccupied
void ensure_load_threshold(int new_used); //Reallocate if load_factor > load_threshold
HashOpenMap<KEY,T,thash>::HashOpenMap(double the_load_threshold, int (*chash)(const KEY& k)): hash(thash != (hashfunc)undefinedhash<KEY> ? thash : chash), load_threshold(the_load_threshold)
{
if (hash == (hashfunc)undefinedhash<KEY>)
throw TemplateFunctionError("HashMap::default constructor: neither specified");
if (thash != (hashfunc)undefinedhash<KEY> && chash != (hashfunc)undefinedhash<KEY> && thash != chash)
throw TemplateFunctionError("HashMap::default constructor: both specified and different");
map = new Entry[bins];
for (int b=0; b<bins; ++b)
map[b] = new bin_state[];
}
I am new to c++. I am currently writing the Constructors for the HashOpenMap. For the above code, I got the following error:
no viable overloaded '='
map[b] = new bin_state[];
any idea how to fix it? thanks in advance.
Make sure you instantiate the same type as the target array element
map[b] = new Entry{};
Also, consider not using new/delete in C++. Or raw C arrays.

Need to reference and update value from nested class C++

Bear with me, I'm new to C++. I'm trying to update a value which is stored in a vector, but I'm getting this error:
non-const lvalue reference to type 'Node'
I'm using a simple wrapper around std::vector so I can share methods like contains and others (similar to how the ArrayList is in Java).
#include <vector>
using namespace std;
template <class T> class NewFrames {
public:
// truncated ...
bool contains(T data) {
for(int i = 0; i < this->vec->size(); i++) {
if(this->vec->at(i) == data) {
return true;
}
}
return false;
}
int indexOf(T data) {
for(int i = 0; i < this->vec->size(); i++) {
if(this->vec->at(i) == data) {
return i;
}
}
return -1;
}
T get(int index) {
if(index > this->vec->size()) {
throw std::out_of_range("Cannot get index that exceeds the capacity");
}
return this->vec->at(index);
}
private:
vector<T> *vec;
};
#endif // A2_NEWFRAMES_H
The class which utilizes this wrapper is defined as follows:
#include "Page.h"
#include "NewFrames.h"
class Algo {
private:
typedef struct Node {
unsigned reference:1;
int data;
unsigned long _time;
Node() { }
Node(int data) {
this->data = data;
this->reference = 0;
this->_time = (unsigned long) time(NULL);
}
} Node;
unsigned _faults;
Page page;
NewFrames<Node> *frames;
};
I'm at a point where I need to reference one of the Node objects inside of the vector, but I need to be able to change reference to a different value. From what I've found on SO, I need to do this:
const Node &n = this->frames->get(this->frames->indexOf(data));
I've tried just using:
Node n = this->frames->get(this->frames->indexOf(data));
n.reference = 1;
and then viewing the data in the debugger, but the value is not updated when I check later on. Consider this:
const int data = this->page.pages[i];
const bool contains = this->frames->contains(Node(data));
Node node = this->frames->get(index);
for(unsigned i = 0; i < this->page.pages.size(); i++) {
if(node == NULL && !contains) {
// add node
} else if(contains) {
Node n = this->frames->get(this->frames->indexOf(data));
if(n.reference == 0) {
n.reference = 1;
} else {
n.reference = 0;
}
} else {
// do other stuff
}
}
With subsequent passes of the loop, the node with that particular data value is somehow different.
But if I attempt to change n.reference, I'll get an error because const is preventing the object from changing. Is there a way I can get this node so I can change it? I'm coming from the friendly Java world where something like this would work, but I want to know/understand why this doesn't work in C++.
Node n = this->frames->get(this->frames->indexOf(data));
n.reference = 1;
This copies the Node from frames and stores the copy as the object n. Modifying the copy does not change the original node.
The simplest "fix" is to use a reference. That means changing the return type of get from T to T&, and changing the previous two lines to
Node& n = this->frames->get(this->frames->indexOf(data));
n.reference = 1;
That should get the code to work. But there is so much indirection in the code that there are likely to be other problems that haven't shown up yet. As #nwp said in a comment, using vector<T> instead of vector<T>* will save you many headaches.
And while I'm giving style advice, get rid of those this->s; they're just noise. And simplify the belt-and-suspenders validity checks: when you loop from 0 to vec.size() you don't need to check that the index is okay when you access the element; change vec.at(i) to vec[i]. And in get, note that vec.at(index) will throw an exception if index is out of bounds, so you can either skip the initial range check or keep the check (after fixing it so that it checks the actual range) and, again, use vec[index] instead of vec.at(index).

Solving leaky memory and syntax issues in a simple hash table

I'm implementing a basic hashtable. My logic for the table makes sense (at least to me), but I'm a bit rusty with my C++. My program returns a free memory error when I run it, but I can't seem to figure out where my problem is. I think is has to do with how I call the pointers in the various class functions.
#include <iostream>
#include <unordered_map>
#include <string>
#include <cmath>
#include <exception>
using namespace std;
int hashU(string in/*, int M*/){ //hThe hash function that utilizes a smal pseusorandom number
char *v = new char[in.size() + 1]; //generator to return an number between 0 and 50. (I arbitrarily chose 50 as the upper limit)
copy(in.begin(), in.end(), v); //First the input string is turned into a char* for use in the the function.
v[in.size()] = '\0';
int h, a = 31415, b = 27183;
for(h=0;*v!=0;v++,a=a*b%(49-1))
h = (a*h + *v)%50;
delete[] v; //Delete the char* to prevent leaky memory.
return (h<0) ? (h+50) : h; //Return number
}
struct hashNode{ //The node that will store the key and the values
string key;
float val;
struct hashNode *next;
};
struct hashLink{ //The linked list that will store additional keys and values should there be a collision.
public:
struct hashNode *start; //Start pointer
struct hashNode *tail; //Tail pointer
hashLink(){ //hashLink constructor
start=NULL;
tail=NULL;
}
void push(string key, float val); //Function to push values to stack. Used if there is a collision.
};
void hashLink::push(string key, float val){
struct hashNode *ptr;
ptr = new hashNode;
ptr->key = key;
ptr->val = val;
ptr->next = NULL;
if(start != NULL){
ptr->next = tail;
}
tail = ptr;
return;
}
struct hashTable{ //The "hash table." Creates an array of Linked Lists that are indexed by the values returned by the hash function.
public:
hashLink hash[50];
hashTable(){ //Constructor
}
void emplace(string in, float val); //Function to insert a new key and value into the table.
float fetch(string in); //Function to retrieve a stored key.
};
void hashTable::emplace(string in, float val){
int i = hashU(in); //Retrieve index of key from hash function.
hashNode *trav; //Create node traveler
trav = hash[i].start; //Set the traveler to the start of the desired linked list
while(trav!=hash[i].tail){ //Traverse the list searching to see if the input key already exists
if(trav->key.compare(in)==0){ //If the input key already exists, its associated value is updated, and the function returns.
trav->val = val;
return;
}
else //Travler moves to next node if the input key in not found.
trav = trav->next;
}
hash[i].push(in,val); //If the traveler does not see the input key, the request key must not exist and must be created by pushing the input key and associated value to the stack.
return;
}
float hashTable::fetch(string in){
int i = hashU(in); //Retrieve index of key
hashNode *trav; //Create node traveler and set it to the start of the appropriate list.
trav = hash[i].start;
while(trav!=hash[i].tail){ //Traverse the linked list searching for the requested key.
if(trav->key.compare(in)==0){ //If the the requested key is found, return the associated value.
return trav->val;
}
else
trav = trav->next; //If not found in the current node, move to the next.
}
return false; //If the requested key is not found, return false.
}
int main(){
hashTable vars; //initialize the hash table
float num = 5.23; //create test variable
vars.emplace("KILO",num);
cout<<vars.fetch("KILO")<<endl;
return 0;
}
The problem is that when you call delete[] v, you have advanced v such that it is pointing to the 0 at the end of the string, which is the wrong address to delete.
Also, you're wasting a lot of code unnecessarily copying the string out of where it is already available as a c-string.
unsigned int hashU(string in/*, int M*/) {
const char* v = in.c_str();
unsigned int h, a = 31415, b = 27183;
for(h=0;*v!=0;v++,a=a*b%(49-1))
h = (a*h + *v);
return h % 50;
}
for(h=0;*v!=0;v++,a=a*b%(49-1))
h = (a*h + *v)%50;
delete[] v; //Delete the char* to prevent leaky
You are incrementing v, then deleting an invalid memory location.

No Appropriate Default Constructor Available despite default constructor made?

Trying to make my own Map struct to store my own-created 'Strings,' and after 8 hours or so finally got it down to only a few compiler errors (six of them). I've spent the last hour and forty minutes searching the web for answers, only to find people forgot default constructors, and tried mixing things up in my own program. Since I'm not really sure where the problem is in advance, I apologize for posting all this code...I put what I thought were the most relevant files first; I think only the first 3 are necessary. The error is
"SubdomainPart' : No appropriate default constructor available" for lines 12 and 20 of the Map.h file.
Map.h
// Map.h - Map template class declaration
// Written by -----
#pragma once
template<typename KEY_TYPE, typename VALUE_TYPE>
struct Map
{
public:
// Default / initial constructor hybrid
Map(int initialCapacity = 10)
{
Size = 0;
Capacity = initialCapacity;
Key;
MappedValue;
//Allocate the C-Array elements using HEAP
Data = new VALUE_TYPE[Capacity];
}
struct iterator
{
KEY_TYPE * current;
KEY_TYPE * prev;
KEY_TYPE * next;
iterator operator ++ ()
{
iterator it = this;
iterator itNext = it.next;
it.next = itNext.next; // pushes iterator forward.
it.prev = it.current;
it.current = it.next;
}
iterator operator -- ()
{
iterator it = this;
iterator itPrev = it.prev;
it.prev = itPrev.prev; // pushes iterator backward.
it.next = it.current;
it.current = it.prev;
}
};
Map(const Map& copyFrom)
{
// Necessary to prevent the delete[] Data; statement in the assignment operator from
// freezing because Data has some garbage address in it.
Data = NULL;
*this = copyFrom; //'this' points to the current instance of the object. (in this case, 'Map')
}
// Destructor: MUST HAVE because we allocate memory
~Map()
{
delete[] Data;
}
Map& operator = (const Map& copyFrom)
{
// 0) delete the old one!
delete[] Data;
// 1) copy Size and Capacity
Size = copyFrom.Size;
Capacity = copyFrom.Capacity;
// 2) Allocate Memory
Map* Data = new Map[Capacity];
// 3) Copy the Map Elements
for(int i = 0; i<Size; i++)
Data[i] = copyFrom.Data[i];
return *this;
}
// Index Operator
VALUE_TYPE& operator[] (KEY_TYPE key) const
{
return Data[key];
}
// Accessor functions: read-only access to Size and Capacity
int GetSize() const //const does not modify ANY data members of the class (size, capacity, or data)
{
return Size;
}
int GetCapacity() const
{
return Capacity;
}
void PushBack(const VALUE_TYPE& newElement) //adds value to end of Map as default
{
if(Size >= Capacity)
increaseCapacity(2 * Capacity);
Data[Size] = newElement;
Size++; // increases size of the array so it can be used later.
}
// Overloaded Add function, inserts a value at specified index, calls in "Insert" to do so.
void Add(const VALUE_TYPE& newElement, int index)
{
if( (index<0) || (index > Size))
{
throw ("Index to insert is out of range");
}
//Make sure there's space!
if (Size >= Capacity)
increaseCapacity(2*Capacity); //increase size of array if too small!
Insert(index, newElement);
}
void Remove(int index) // index = index to be removed.
{
// Make sure it's inside the bounds
if( (index<0) || (index > Size))
{
throw ("Index to Remove is out of range.");
}
// it's going to remove the unneeded space by having its capacity one above the Size.
Map* new_Data = new Map[Size];
//Copy data onto new pointer section.
for(int x = 0; x<Size; x++)
new_Data[x] = Data[x];
delete[] Data; //deallocates old memory and uneeded capacity slots.
for(int x = index; x < (Size - 1); x++) //removes the value at index 'index.' Now Data has a capacity of the amount of slots used and one more for a NULL value.
new_Data[x] = new_Data[x+1];
Data = new_Data;
Data[Size-1] = NULL;
Size--;
}
void increaseCapacity(int new_capacity)
{
if(new_capacity>Capacity)
{
if(new_capacity> 2* Capacity)
Capacity = new_capacity;
else
Capacity *= 2;
//create Map with a new capacity!
Map* new_Map = new Map[Capacity];
for(int x = 0; x<Size; x++)
{
new_Map[x] = Data[x];
}
//clear out old memory
delete[] Data;
//set data pointer to the new Map
Data = new_Map;
}
}
KEY_TYPE * Key; // Used to identify mapped values.
VALUE_TYPE MappedValue; // The value actually contained.
private:
int Size; // The count of actual C-Array elements used
int Capacity; // The count of C-array elements allocated
// The encapsulated C-array
VALUE_TYPE * Data; // pointer of type 'DATA_TYPE' called data (will be name of our array).
void Insert(const int index, const VALUE_TYPE& insertValue)
{
if( (index<0) || (index > Size))
{
throw out_of_range ("Index to insert is out of range");
}
//Time to shuffle the array down!
for(int x = Size; x>index; x--)
{
Data[x] = Data[x-1];
}
//Insert the new item at index 'Index!'
Data[index] = insertValue;
Size++;
}
};
SubdomainPart.h
// SubdomainPart.h - SubdomainPart validation class declaration
// Written by -------
#pragma once
#include "String.h"
using namespace std;
class SubdomainPart
{
public:
// Takes the address and stores into the Address data member
SubdomainPart(const String& address);
// Returns true when the Address is valid or false otherwise
virtual bool IsValid();
private:
String Address;
};
SubdomainPart.cpp
// SubdomainPart.cpp - Subdomain validation class implementation
// Written by ---------
#pragma once
#include "SubdomainPart.h"
// Takes the address and stores into the Address data member
SubdomainPart::SubdomainPart(const String& address)
{
Address = address;
}
// Returns true when the Address is valid or false otherwise
bool SubdomainPart::IsValid()
{
int currentDotIndex = 0;
int nextDotIndex = 0;
int found = 0; // first index of a found invalid character
int hyphenIndex = 0; // used to check hyphen rule
// 1. Check the size, 255 total characters
if(Address.GetLength() < 1 || Address.GetLength() > 255)
return false;
// Checks for valid amount of 1-63 characters between dots
currentDotIndex = Address.FindFirstOf('.');
if(currentDotIndex == 0 || currentDotIndex == Address.GetLength()-1)
return false;
else if(currentDotIndex!=(-1))
nextDotIndex = Address.Find('.', currentDotIndex+1);
else
nextDotIndex = (-1); // if no '.' is found, ensures the following loop doesn't run.
while(nextDotIndex!=(-1))
{
if((nextDotIndex-currentDotIndex) == 1 || (nextDotIndex-currentDotIndex) > 63)
return false;
currentDotIndex = nextDotIndex;
nextDotIndex = Address.Find('.', currentDotIndex+1);
}
// 2. Check for valid characters
found = Address.FindFirstNotOf("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890-.");
if(found!=(-1)) // if a character not listed above is found.
return false;
// 3. Check for dash rule
// Making sure hyphens aren't located at the first or last index of a subdomain.
hyphenIndex = Address.FindFirstOf('-');
if(hyphenIndex == 0)
return false;
hyphenIndex = Address.FindLastOf('-');
if(hyphenIndex == Address.GetLength()-1)
return false;
// Makes sure two hyphens aren't in a row.
for(int x = 1; x<Address.GetLength(); x++)
if(Address[x] == '-' && Address[x] == Address[x-1])
return false;
return true;
}
I don't see a default constructor in this class:
class SubdomainPart
{
public:
// Takes the address and stores into the Address data member
SubdomainPart(const String& address);
// Returns true when the Address is valid or false otherwise
virtual bool IsValid();
private:
String Address;
};
Keep in mind that this map constructor is default-constructing every member rather than initializing them:
Map(int initialCapacity = 10)
{
Size = 0;
Capacity = initialCapacity;
Key;
MappedValue;
//Allocate the C-Array elements using HEAP
Data = new VALUE_TYPE[Capacity];
}
You don't have a default constructor for SubdomainPart you have only provided a copy constructor. A default constructor takes no argument.
The compiler is complaining that SubdomainPart doesn't have a default constructor, and indeed it doesn't. It's required because your Map contains an object of type VALUE_TYPE:
VALUE_TYPE MappedValue;
Also, your Map constructor contains very weird code. I assume you actually wanted to use an initialiser list:
Map(int initialCapacity = 10)
: Key()
, MappedValue()
, Size(0)
, Capacity(initialCapacity)
, Data(new VALUE_TYPE[Capacity])
{}
The problem is with Data = new VALUE_TYPE[Capacity]; part.
The compiler generates code to allocate the array and instantiate each element by calling the parameterless constructor for VALUE_TYPE. As SubdomainPart doesn't have one (since you have defined a custom one), the compiler throws an error.
The reason that compiler reports error in map.h is that it is exactly the place where the constructor is called from. It is not used in SubdomainPart code, it is just defined there.