Search code examples
c++arraysvectorsegmentation-fault

Attempting to build Dynamic Array from scratch: Segmentation Fault when using delete[] in append function


I am attempting to build a C++ vector from scratch for an assignment, but I've been struggling all day. My append function is broken. At first it would take no string input, but I've gotten it to append one string to the dynamic list. However, when I attempt to append a second string to the list, the temp array is appended with that string, but when I go to delete the existing data attribute array that second time (the previous temp array), I get a segmentation fault. I've included a lot of print statements to pinpoint this.

I have tried instantiating a block of objects using placement new since strings are objects. Here is the DynamicList class.cpp file:

#include <iostream>
#include <string>
#include "DynamicList.hpp"
#include <algorithm>
 
//Constructor
template<typename T>
DynamicList<T>::DynamicList(){
        size = 0;
        data = new T[size];
}
 
//Destructor
template<typename T>
DynamicList<T>::~DynamicList(){
        std::cout << "Deleting array of size: " << getSize() << std::endl;
        delete[] data;
 
}
 
//Overloading operators
template<typename T>
DynamicList<T> DynamicList<T>::operator=(DynamicList<T>& obj){
        obj.size = size;
        std::copy(data, data + size, obj.data);
}
template<typename T>
bool DynamicList<T>::operator==(DynamicList<T>& obj){
        if(size != obj.size){
                return false;
        }
        else{
                for(int i = 0; i < size; i++){
                        if(obj.data[i] != data[i]){
                                return false;
                        }
                }
                return true;
        }
 
}
 
template<typename T>
bool DynamicList<T>::operator!=(DynamicList<T>& obj){
        return !(DynamicList<T>::operator==(obj));
}
 
template<typename T>
T DynamicList<T>::operator[](int index){
        for(int i = 0; i < size; i++){
                if(i == index){
                        return data[i];
                }
        }
}
//Returns the size of the list
template<typename T>
int DynamicList<T>::getSize(){
        return size;
}
//Add element to the end of list.
template<typename T>
bool DynamicList<T>::append(T item){
        std::cout << data << std::endl;
        std::cout << item << std::endl;
 
        T* temp = static_cast<T*>(new T(sizeof(T) * (size + 1), alignof(T)));
        if(size > 1){
                for(int i = 0; i < size; i++){
                        T* somePtr = new (&temp[i]) T;
                        *somePtr = data[i];
                }
        }
        T* itemPtr = new (&temp[size]) T;
        *itemPtr = item;
        std::cout << "Ptr made in array slot.\n";
        std::cout << temp << std::endl;
        size++;
        std::cout << "Size increased.\n";
 
        std::cout << data << std::endl;
        std::cout << "AAAAAA\n";
        delete[] data;
        std::cout << "BBBBB\n";
        data = temp;
        std::cout << data[size - 1] << std::endl;
        return true;
}

Here is the header file for DynamicList:

#include <iostream>
#include <string>

#ifndef DYNAMICLIST_H
#define DYNAMICLIST_H

template<typename T>
class DynamicList{

        private:
                int size;
                T* data;
        public:
                //constructor
                DynamicList();
                //destructor
                ~DynamicList();
                //Operator overloaders
                DynamicList operator=(DynamicList& obj);
                bool operator==(DynamicList& obj);
                bool operator!=(DynamicList& obj);
                T operator[](int index);
                //Returns the size of the data array
                int getSize();
                //Add an item to the end of the list
                bool append(T item);
                //Remove an item at an index
                bool remove(int index);
};

#endif

Here is the main file:

#include <iostream>
#include <string>
#include "DynamicList.hpp"
#include "DynamicList.cpp"

int main(){

        DynamicList<std::string> stringList;

        stringList.append("test");
        stringList.append("test2");

        return 0;
}

Here is the makefile:

all: DynamicList.hpp DynamicList.cpp main.cpp
        g++ -c DynamicList.cpp
        g++ -c main.cpp
        g++ DynamicList.o main.o -o exec

run: all
        ./exec

clean:
        rm -f *.o
        rm -f exec

Here is the error:

./exec
0x55c688824eb8
test
Ptr made in array slot.
0x55c6888252f0
Size increased.
0x55c688824eb8
AAAAAA
BBBBB
test
0x55c6888252f0
test2
Ptr made in array slot.
0x55c688824eb0
Size increased.
0x55c6888252f0
AAAAAA
make: *** [makefile:8: run] Segmentation fault (core dumped)

Solution

  • The constructor creates the array with array new[], but the append function uses object new instead. Deleting objects created with object new using array delete[] or vice versa is undefined behavior.

    You should replace the object new in append with array new[]:

    template<typename T>
    bool DynamicList<T>::append(T item) {
            T* temp = new T[size + 1];
    
            for (int i = 0; i < size; i++) {
                    temp[i] = data[i];
            }
            temp[size] = item;
            size++;
     
            delete[] data;
            data = temp;
            return true;
    }