Как я могу создать деструктор, чтобы проверить, является ли указатель NULL? Если нет, удалите память, выделенную для указателя

CheckedArray::CheckedArray(int size) :mSize(size){
    int *mArray = new int[size];
    for(int i = 0; i < size; i++)
          mArray[i] = 0;
}

CheckedArray::~CheckedArray() {
    if (mArray == NULL){
        return;
    }
    else {
        delete[] mArray;
    }
}

Я использую динамическое выделение памяти для создания нового массива. Я хочу проверить, является ли указатель нулевым, а затем вернуться. Если нет, то удалите. Я получаю эти сообщения об ошибках, но я понятия не имею, что не так.

(9094,0x100094600) malloc: *** ошибка для объекта 0x10001e7b3: освобождаемый указатель не был выделен

(9094,0x100094600) malloc: *** установить точку останова в malloc_error_break для отладки

Почему бы не использовать std::unique_ptr<int[]>? избегайте явного вызова new/delete и сделайте его переменной-членом

Pepijn Kramer 02.02.2023 07:43
int *mArray = new int[size]; создает локальную переменную и утечку памяти, поскольку после завершения функции указатель теряется. Если у вас есть переменная-член с именем mArray, вы должны использовать вместо нее mArray = new int[size];. Нет необходимости проверять, является ли указатель NULL или нет перед его удалением. Удаление указателя NULL — это нормально, это просто недопустимо.
Retired Ninja 02.02.2023 07:43

Другие примечания: не используйте NULL, а используйте nullptr в C++. И во всех ваших конструкторах инициализируйте указатель переменной-члена на nullptr, если вы действительно не выделяете память.

Pepijn Kramer 02.02.2023 07:44

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

Some programmer dude 02.02.2023 07:45

Также обратите внимание, что, как и для free, delete и delete[] изящно обрабатывают нулевые указатели и ничего не делают в этом случае. Поэтому никогда не нужно проверять наличие нулевых указателей перед освобождением памяти.

Some programmer dude 02.02.2023 07:48

Также помните, что если класс владеет ресурсом , он также отвечает за правильное копирование и перемещение этого ресурса .

user4581301 02.02.2023 07:53

По умолчанию выражение new не может возвращать нулевой указатель (вместо этого оно генерирует исключение). Таким образом, деструктору не нужно проверять, является ли mArray значением null, если конструкторы (и другие функции-члены, изменяющие mArray) ведут себя разумно. Поскольку у вас есть один конструктор с выражением new, я подозреваю, что ваша реальная проблема заключается в том, что вы не следовали «правилу трех» или (возможно) «правилу пяти» - в результате чего ваш деструктор для некоторых объектов delete[]ing одни и те же данные дважды (вызывая неопределенное поведение).

Peter 02.02.2023 08:01
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
7
58
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Вот пример того, что std::unique_ptr может сделать для вас:

#include <iostream>
#include <algorithm>
#include <memory>

// https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#r11-avoid-calling-new-and-delete-explicitly
// so use https://en.cppreference.com/w/cpp/memory/unique_ptr/make_unique
// prefer range based for loops, they can't go out of bounds : https://en.cppreference.com/w/cpp/language/range-for

class dynamic_int_array_t final
{
public:
    // creates an "empty array" with enough memory for 4 ints.
    dynamic_int_array_t() :
        m_capacity{ 4ul },  // start with a capacity for 4 ints.
        m_size{ 0ul },      // but actually none are stored yet
        m_values{ std::make_unique<int[]>(m_capacity) }
    {
    }

    // allows you to construct an array from a list of integers
    dynamic_int_array_t(std::initializer_list<int>&& values) :
        m_capacity{ values.size() },
        m_size{ values.size() },
        m_values{ std::make_unique<int[]>(m_capacity) }
    {
        std::copy(values.begin(), values.end(), m_values.get());
    }

    ~dynamic_int_array_t() = default; // destructor will destruct unique_ptr and free memory

    // non-copyable non-movable (simplifies things for now)
    dynamic_int_array_t(const dynamic_int_array_t&) = delete;
    dynamic_int_array_t& operator=(const dynamic_int_array_t&) = delete;
    dynamic_int_array_t(dynamic_int_array_t&&) = delete;
    dynamic_int_array_t& operator=(dynamic_int_array_t&&) = delete;

    // begin and end allow range based for loops to work
    // range based for loops don't allow you to go out of bounds.
    auto begin() const
    {
        return m_values.get();
    }

    // end should point "one past" the array (that's how end works)
    auto end() const
    {
        int* ptr = begin();
        ptr += m_size;
        return ptr;
    }

    std::size_t size() const
    {
        return m_size;
    }

    void add(const int value)
    {
        // if not enough memory then allocate more
        if (m_size == m_capacity) grow_capacity();

        // add new value at the end
        m_values[m_size] = value;
        m_size++;
    }

    // add another array to this one
    void append(const dynamic_int_array_t& rhs)
    {
        for (int value : rhs)
        {
            add(value);
        }
    }

private:

    void grow_capacity()
    {
        m_capacity *= 2;

        // allocate new memory
        auto tmp = std::make_unique<int[]>(m_capacity);

        // copy content to new memory
        std::copy(begin(), end(), tmp.get());

        // swap new memory with tmp so m_values will now be the newly allocated memory and tmp will hold the previously allocated memory
        std::swap(tmp, m_values);

        // tmp will go out of scope and delete old buffer
    }

    std::size_t m_capacity;
    std::size_t m_size;
    std::unique_ptr<int[]> m_values;
};

int main()
{
    dynamic_int_array_t array{ 4,5 };

    for (int n = 10; n < 20; ++n)
    {
        array.add(n);
    }

    for (const int value : array)
    {
        std::cout << value << " ";
    }
    

    return 0;
}
Ответ принят как подходящий

Чтобы было совершенно ясно

CheckedArray::CheckedArray(int size) :mSize(size){
    int *mArray = new int[size];
    for(int i = 0; i < size; i++)
          mArray[i] = 0;
}

должно быть

CheckedArray::CheckedArray(int size) :mSize(size), mArray(new int[size]){
    for(int i = 0; i < size; i++)
          mArray[i] = 0;
}

Ваша версия создает локальную переменную mArray, которая скрывает одноименную переменную класса.

Другие вопросы по теме