При использовании списка инициализатора возникает ошибка повреждения кучи - PullRequest
0 голосов
/ 08 апреля 2019

У меня есть класс, где я делаю массив в куче.Позже я увеличу размер этого массива.Когда класс создан, я инициализирую массив.Если я делаю это в списке инициализаторов, я получаю «ошибку повреждения кучи» при увеличении размера массива, но это не происходит, если я не использую список инициализаторов.

Обратите внимание, что я не создал класс с обоими этими конструкторами, а только с одним из них на тот момент.
Почему он не работает должным образом при использовании списка инициализатора?

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

Пример использования кода, в котором происходит сбой:

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

    return 0;
}

1 Ответ

4 голосов
/ 08 апреля 2019

проблема с

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

Работает так, как работают списки инициализаторов элементов (https://en.cppreference.com/w/cpp/language/initializer_list). В разделе под названием «Порядок инициализации» говорится:

элементы нестатических данных инициализируются в порядке объявления в определение класса

Это означает, что из-за определения вашего класса m_arr(new T[m_capacity]) выполняется до m_capacity(1), что означает, что new[] использует неинициализированную переменную, что приводит к неопределенному поведению

...