AJ Jones
AJ Jones

Reputation: 13

Heap corruption error occurs when using initializer list

I have a class, where I make an array on the heap. Later on I'm increasing the size of this array. When the class is constructed, I initialize the array. If I do this in the initializer list I get 'heap corruption error' when increasing the size of the array, but it doesn't occur if I don't use the initializer list.

Note that I haven't made a class with both those constructors, but only one of them at the time.
Why does it not work as expected when the initailizer list is used?

template <typename T>
class Vector {
public:
    Vector() noexcept;

    void push_back(const T& t);

private:
    T* m_arr;
    unsigned int m_size;
    unsigned int m_capacity;

    void realloc();

};

template<typename T>
inline Vector<T>::Vector() noexcept
    : m_size(0), m_capacity(1) {
    m_arr = new T[m_capacity];
    // realloc() works fine with this constructor.
}

template<typename T>
inline Vector<T>::Vector() noexcept
    : m_size(0), m_capacity(1), m_arr(new T[m_capacity]) {
    // Error occurs in realloc() with this constructor.
}

template<typename T>
inline void Vector<T>::push_back(const T& t) {
    if (m_size == m_capacity) {
        m_capacity <<= 1;
        realloc();
    }

    m_arr[m_size] = t;
    ++m_size;
}

template<typename T>
inline void Vector<T>::realloc() {
    T* newArr = new T[m_capacity];
    memcpy(newArr, m_arr, m_size * sizeof(T));
    delete[] m_arr; // Error occurs here with initializer list constructor.
    m_arr = newArr;
}

An example usage of the code where it crashes:

int main() {
    Vector vec;
    vec.push_back(0);
    vec.push_back(0); // Crashes here
    vec.push_back(0);

    return 0;
}

Upvotes: 0

Views: 277

Answers (1)

UnholySheep
UnholySheep

Reputation: 4096

The problem with

template<typename T>
inline Vector<T>::Vector() noexcept
    : m_size(0), m_capacity(1), m_arr(new T[m_capacity]) {}

Lies in the way that member initializer lists work (https://en.cppreference.com/w/cpp/language/initializer_list). In the section titled "Initialization order" it states:

non-static data members are initialized in order of declaration in the class definition

This means that due to your class definition m_arr(new T[m_capacity]) gets executed before m_capacity(1) which means that the new[] uses an uninitialized variable, thus leading to undefined behavior

Upvotes: 4

Related Questions