-4

When I run it with the data type integer, it works perfectly fine but when I run it with string, it does not work.

Container storage capacity = 2. Currently, container contains 2 elements. The contents of the container: aaa bbb

after this output, it does not go further.

I do not know if the problem is about allocate function.

[Done] exited with code=3221226356 in 0.518 seconds This is the error I got

people are saying that this error is heap corruption. but I do not even know what that means and how to fix it. I just started to learn coding. I am sorry for my ignorance.

#include <iostream>
#include <String>
using namespace std;

template <class T>
class container
{
    template <class S>
    friend ostream& operator<<(ostream& out, container<S> &cobj);
    // Postcondition: contents of the container object cobj is displayed

public:
    container();
    // Postcondition: an empty container object is created with data members arr set to NULL, n set to -1 and Capacity set to 0

    container(container<T> &cobj);
    // copy constructor; required as one of the Big-3 (Big-5) because of the presence of a pointer data member
    // Postcondition: a new container object is created as a "deep" copy of cobj. (the default version creates a “shallow” copy!)

    container(T* start, T* end);
    // 3rd constructor; maps or copies the contents of a T-type array from a[start]...a[end] to the newly created container object. 
    //  Note:  'end' is the address of the imaginary element to the immediate right of the last array element
    // Postcondition: the arr array of the newly created container object has been initialized with the contents of T-type array

    ~container();
    // Destructor; required as one of the Big-3 (or Big(5) because of the presence of a pointer data member. Default version results in 
    //    memory leak!
    // Postcondition: dynamic memory pointed to by arr has been release back to the “heap” and arr set to NULL or nullptr
    //                 In order to see the action, message "destructor called and dynamic memory released!" is displayed

    container operator=(container<T> &cobj2);
    // overloaded assignment operator. The default version cannot be used because it results in a shallow copy!
    // Postcondition: cobj2 is assigned to the calling object

    bool isEmpty();
    // Postcondition: returns true is nothing is stored; returns false otherwise

    bool isFull();
    // Postcondition: returns true if arr array is filled to capacity; returns false otherwise

    int size();
    // Postcondition: returns the size or the number of elements (values) currently stored in the container

    int capacity();
    // Postcondition: returns the current storage capacity of the container

    void insertBack(T &newVal);
    // Postcondition: if container is not full, newVal is inserted at the end of the array; 
    //                otherwise, double the current capacity followed by the insertion

    bool deleteBack();
    //  Precondition: The array must not be empty
    // Postcondition: the last element stored in the array is removed! size of the container is decremented by 1, capacity unchanged

    void insertFront(T &newVal);
    // Postcondition: returns true if the container is not full and newVal is inserted at the front of the array; 
    //                otherwise, double the current storage capacity followed by the insertion

    bool deleteFront();
    // Postcondition: front element of arr is deleted, all other elements in arr are left-shifted by one position; 
    //                 size of arr is decremented by 1, capacity remains unchanged.

    void insertSorted(T newVal);
    // Postcondition: newVal is inserted in arr of the container object in such a way that the resulting arr array remains sorted

    void clear();
    // Postcondition: all elements in arr of calling container object are cleared and the dynamic memory is released back to “heap” 

    int linearSearch(T target);
    // Linear search the arr array for the existence of the target value
    // Postcondition: if target value is found, returns sub of arr[sub] in which the target value is stored; otherwise returns -1 

    int binarySearch(T target);
    //  Precondition: the array arr must be sorted (ascending order is assumed) 
    // Postcondition: if target is found, returns value of the sub in arr[sub] where the target value is stored; otherwise returns -1 

    void sort();
    // Use a sort algorithm you have not used before (e.g., selection sort, insertion  sort, etc. assuming you had used bubble sort already.
    // Postcondition: the array arr of the container class in ascending order

    bool insertPos(int sub, T newVal);
    //  Precondition: 1) 0 <= sub <= n; i.e., it must be within the range of the arr array.
    // Postcondition: If sub is in range, newVal is inserted in arr[sub]; affected elements from arr[sub] ... arr[n] are right- shifted one step 

private:
    void shiftRight();
    // shift arr[n] ... arr[0] to arr[n+1]...arr[1] to make arr[0] available to store the inserted value 
    // Postcondition: all elements from arr[0] to arr[n] are shift one position to the right

    void shiftLeft();
    // shift arr[1] ... arr[n] to a arr[0]...arr[n-1]  
    //  Precondition: the container must not be empty
    // Postcondition: all element from arr[1] to arr[n-1] are shifted one position to the left

    void allocate(T* &temp);
    // Postcondition: if Capacity = 0, allocate a single location; otherwise the current capacity is doubled
    T *arr;
    int Capacity;   // Note: Capital 'C' as capacity is used as a function name
    int n;          // size or actual # of values currently stored in the container; n <= SIZE
};

template <class T>
ostream& operator<<(ostream& out, container<T> &cobj)
{
    out << "Container storage capacity = " << cobj.Capacity << endl;
    out << "Currently, container contains " << cobj.size() << " elements." << endl;
    out << "The contents of the container:" << endl;

    if(cobj.size() == 0)
        out << "***Container is empty!!" << endl;
    else{
        for(int i = 0; i <= cobj.n; i++){
            out << cobj.arr[i] << " ";
        }

        out << endl;

    }
        
    return out;
}

template <class T>
container<T>::container()
{
    arr = nullptr;
    n = -1;
    Capacity = 0;
}

template <class T>
container<T>::~container()
{
    clear();
    cout << "Destructor called and dynamic memory released!" << endl;
}

template <class T>
bool container<T>::isEmpty()
{
    return (n == -1);
}

template <class T>
bool container<T>::isFull()
{
    return (n == Capacity-1);
}

template <class T>
int container<T>::size()
{
    return n+1;
}


template <class T>
int container<T>::capacity()
{
    return Capacity;
}

template <class T>
void container<T>::insertBack(T &newval1)
{
    allocate(arr);
    n++;
    arr[n] = newval1;
}

template <class T>
bool container<T>::deleteBack()
{
    if(isEmpty())
        return false;
    else{
        n--;
        return true;
    }

}

template <class T>
void container<T>::insertFront(T &newval)
{
    allocate(arr);
    for(int i = n; i > -1; i--){
        arr[i+1] = arr[i];
    }
    n++;
    arr[0] = newval;
}

template <class T>
bool container<T>::deleteFront()
{
    if(isEmpty())
        return false;
    else{
        for(int i = 1; i <= n; i++){
            arr[i-1] = arr[i];
        }
        n--;
        return true;
    }

}

template <class T>
void container<T>::clear()
{
    delete arr;
    arr = nullptr;
    Capacity = 0;
    n = -1;
}

template <class T>
void container<T>::allocate(T* &temp)
{
    if(Capacity == 0){
        temp = new T;
        Capacity = 1;
    }else{
        Capacity *= 2;
        T *tmp = new T[Capacity];

        for(int i = 0; i <= n; i++)
        {
            tmp[i] = temp[i];
        }
         
        delete temp;
        temp = tmp;
    }
        
}

int main()
{
    container<string> obj;
    cout << obj << endl << endl;

    string array[] = {"aaa", "bbb", "ccc"};

    cout << "Currently, the container object contains " << obj.size() << " elements or values" << endl << endl;
    cout << "Now we insert 3 values at the back of the array, one at a time:" << endl;


    for(int i = 0; i < 3; i++){
        obj.insertBack(array[i]);
        cout << obj << endl;
    }

    cout << "Now we delete all 3 values from the back of the array, one at a time:" << endl << endl;

    bool res;

    for(int i = 0; i < 3; i++){
        res = obj.deleteBack();

        if(!res){
            cout << "We cannot delete from an empty array" << endl;
            break;
        }else
            cout << obj << endl;
    }

    cout << "Now we try to delete from an empty container: "<< endl << endl;

    res = obj.deleteBack();
    if(!res)
        cout << "We cannot delete from an empty array" << endl << endl;
    else
        cout << obj << endl;
    
    /*cout << "Now we insert 3 values at the front of the array, one at a time:" << endl << endl;

    for(int i = 0; i < 3; i++){
        obj.insertFront(array[i]);
        cout << obj << endl;
    }

     cout << "Now we delete all 3 values from the back of the array, one at a time:" << endl << endl;

    for(int i = 0; i < 3; i++){
        res = obj.deleteFront();

        if(!res){
            cout << "We cannot delete from an empty array" << endl;
            break;
        }else
            cout << obj << endl;
    }*/



   

    return 0;
}
atanaka
  • 1
  • 3
  • 2
    Why did you repeat your statement multiple times and not post the exact text of the error message? – drescherjm Oct 26 '21 at 14:11
  • 3
    Instead of spamming the question add the error message to it. – B001ᛦ Oct 26 '21 at 14:11
  • 4
    Please create a [mcve] and try to write a comprehensible description of your problem. "When I run it with the data type , it works perfectly fine but when I run it with , it does not work." is nonsense. – molbdnilo Oct 26 '21 at 14:12
  • Welcome to Stack Overflow! Your question is not clear. Please elaborate on what you are trying to ask. To learn more about this community and how we can help you, please start with the [tour] and read [ask] and its linked resources. – David Oct 26 '21 at 14:13
  • If `n` is actually the number of elements many of your loops need to be altered from `i <= n` to `i < n`. I think you have n defined as the number of elements minus 1 but your comment regarding this to me is a little confusing. – drescherjm Oct 26 '21 at 14:18
  • Address sanitizer finds memory issue: https://godbolt.org/z/q3849exE7 – Marek R Oct 26 '21 at 14:22
  • My advice to you if this is a runtime error and not a compile error is to use a debugger and step through a simple example. Set a breakpoint and step through the code line by line looking at the variables and flow after each statement is executed. – drescherjm Oct 26 '21 at 14:22
  • Related to the mixing of new[] and delete, I question if you want to allocate space for just 1 element on the first allocate or should you allocate more than 1 on the first allocation? – drescherjm Oct 26 '21 at 14:34
  • `3221226356` is `0xC0000374` on windows and means heap corruption. – drescherjm Oct 26 '21 at 14:37
  • The answer explains the problem and how to fix it. What you new you must delete. What you new[] you must delete []. You can't mix these two. It's undefined behavior to mix. There should be more questions here about that. – drescherjm Oct 26 '21 at 14:44
  • Related: [https://stackoverflow.com/questions/1913343/how-could-pairing-new-with-delete-possibly-lead-to-memory-leak-only](https://stackoverflow.com/questions/1913343/how-could-pairing-new-with-delete-possibly-lead-to-memory-leak-only) – drescherjm Oct 26 '21 at 14:50
  • 1
    HRESULT decoder: [3221226356](https://james.darpinian.com/decoder/?q=3221226356) – Eljay Oct 26 '21 at 19:24
  • 1
    @Eljay Thanks for that link. That will save me some work. I normally paste the value into calculator to convert to hex then Google the hex if it looks like a windows error code. – drescherjm Oct 28 '21 at 14:18

1 Answers1

1

I run your code using address sanitizer and issue become clear quite fast.

You are mixing pairs of operators new/delete and new[]/delete[]. If something was allocated with new must be deleted with delete, and If something was allocated with new[] must be deleted with delete[], and

After fixing this in your code it seems to work fine.

template <class T>
void container<T>::clear() {
    delete[] arr;
    arr = nullptr;
    Capacity = 0;
    n = -1;
}

template <class T>
void container<T>::allocate(T *&temp) {
    if (Capacity == 0) {
        temp = new T[1];
        Capacity = 1;
    } else {
        Capacity *= 2;
        T *tmp = new T[Capacity];

        for (int i = 0; i <= n; i++) {
            tmp[i] = temp[i];
        }

        delete[] temp;
        temp = tmp;
    }
}

No warranties. I didn't analyze your code, I just follow problems found by address sanitizer.

Learn to use some debugger ASAP. It is usually integrated with IDE. When program crashes (your problem) it will point help you to find problems.

Marek R
  • 32,568
  • 6
  • 55
  • 140
  • Thank you so much!! I really appreciate you being patient and helping me who is new to programming. You are awesome – atanaka Oct 26 '21 at 14:50