Reciever80
Reciever80

Reputation: 105

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;
}

Upvotes: 1

Views: 1313

Answers (4)

Zdeslav Vojkovic
Zdeslav Vojkovic

Reputation: 14591

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.

Upvotes: 1

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])
{}

Upvotes: 1

Pubby
Pubby

Reputation: 53067

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];
}

Upvotes: 1

Ivaylo Strandjev
Ivaylo Strandjev

Reputation: 70989

You don't have a default constructor for SubdomainPart you have only provided a copy constructor. A default constructor takes no argument.

Upvotes: 1

Related Questions