0

For learning purposes, I'm attempting to create a primitive ArrayList class with the ability to add elements and resize itself when needed. Currently, I managed to create a constructor and overload the array access operator as well as add an append function to add elements to the back of the array. However, once the realloc is triggered, the program crashes with Segmentation Fault: 11. Oddly, though, if I change my code, the first time I execute it there is no segmentation fault; only when rerunning the executable does it fail, so I am suspicious my free() call is not working properly. All elements until the reallocation appear to be successfully added.

I have my class defined in a .cpp file because template definitions are unable to be split into a header and other file.

structures.cpp

#include <cstdlib>
#include <stdexcept>

template<typename T> class ArrayList {
    private:
        T* pointer;
        unsigned short space;
    public:
        ArrayList();
        ~ArrayList();
        T& operator[](unsigned short index);
        const T& operator[](unsigned short index) const; 
        unsigned short length;
        void append(T element);
};

template<typename T> ArrayList<T>::ArrayList() {
    length = 0;
    space = 10;
    pointer = (T*)malloc(space*sizeof(T));
}

template<typename T> ArrayList<T>::~ArrayList() {
    free(pointer);
}

template<typename T> T& ArrayList<T>::operator[](unsigned short index) {
    if (index > length) throw std::out_of_range("Index out of bounds.");
    return *(pointer + sizeof(T)*index);
}

template<typename T> void ArrayList<T>::append(T element) {
    if (length == space) {
        space *= 2;
        pointer = (T*)realloc(pointer, sizeof(T)*space);
    }
    *(pointer + sizeof(T)*length) = element;
    ++length;
}

main.cpp

#include <iostream>
#include "structures.cpp"

int main(int argc, char** argv) {
    ArrayList<unsigned> arr;
    int l = 11;
    for (int i = 0; i < l; ++i) {
        std::cout << "Current index: " << i << std::endl;
        arr.append(i);
    }
    std::cout << "Finished writing to array" << std::endl;
    for (int i = 0; i < l; ++i) {
        std::cout << "Index: " << i << " Value: " << arr[i] << std::endl;
    }
    return 0;
}

Output:

Current index: 0
Current index: 1
Current index: 2
Current index: 3
Current index: 4
Current index: 5
Current index: 6
Current index: 7
Current index: 8
Current index: 9
Current index: 10
Segmentation fault: 11
Neil A.
  • 841
  • 7
  • 23
  • 1
    Besides the already-posted answer. your array template class [violates the Rule Of Three](https://stackoverflow.com/questions/4172722/what-is-the-rule-of-three); additionally it results in undefined behavior for non-POD `T`s, but that's not relevant to the reason for your actual crash. – Sam Varshavchik Jul 06 '18 at 02:19

1 Answers1

0

The problem is here (in your append function):

*(pointer + sizeof(T)*length) = element;

You forget that pointer is a pointer to (the first element of) an array of T elements, and not an array of bytes. What you're doing is (exactly) equal to

pointer[sizeof(T)*length] = element;

which is clearly wrong and can easily be out of bounds and lead to undefined behavior.

The correct way is simply

pointer[length] = element;

Or if you're forced to use explicit pointer arithmetic (I see no other reason)

*(pointer + length) = element;
Some programmer dude
  • 400,186
  • 35
  • 402
  • 621