Массив структур и новое / удаление

У меня есть такая структура:

class Items 
{
private:
    struct item
    {
        unsigned int a, b, c;
    };
    item* items[MAX_ITEMS];
}

Скажем, я хотел «удалить» элемент, например:

items[5] = NULL;

И позже я создал новый элемент на том же месте:

items[5] = new item;

Мне все еще нужно вызвать в delete[], чтобы убрать это? Или это не понадобится, поскольку границы массива items[] известны до компиляции?

Является ли установка этого указателя на NULL действительной или мне следует вызывать там удаление?

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

Ответы 8

C++ не моя сильная сторона, но я почти уверен, что у вас будет утечка памяти, если вы установите указатель на NULL.

Обновлено: утечка памяти будет памятью, на которую указывает указатель в массиве.

Установка элемента [5] в NULL не удаляет память, связанную с элементом, она просто устанавливает указатель на этот элемент в NULL, поэтому происходит утечка памяти.

Вы можете удалить элемент, позвонив:

delete items[5];

Поскольку в C++ нет автоматической сборки мусора, вам нужно удалить всю память, которая вам больше не нужна.

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

Перед установкой значения NULL необходимо вызвать delete. (Установка значения NULL не требуется, это просто помогает уменьшить количество ошибок, если вы случайно попытаетесь разыменовать указатель после его удаления.)

Помните, что каждый раз, когда вы используете new, вам нужно будет использовать delete позже с тем же указателем. Никогда не используйте одно без другого.

Кроме того, new [] и delete [] работают вместе одинаково, но никогда не следует смешивать new [] с delete или new с delete []. В вашем примере, поскольку вы создали объект с помощью new (а не new [], который создавал бы массив объектов), вы должны удалить объект с помощью delete (а не delete []).

Как заметил Клюге, вот так вы бы потеряли объект с индексом 5. Но это действительно звучит так, как будто вы не должны делать это вручную, а используйте класс контейнера внутри Item. Если вам на самом деле не нужно хранить эти объекты item в качестве указателей, используйте std::vector<item> вместо этого массива указателей MAX_ITEMS. Вы всегда можете вставить или стереть векторные элементы посередине, если вам нужно.

Если вам нужно сохранить объекты как указатели (обычно, если struct item действительно полиморфна, в отличие от вашего примера), вы можете вместо этого использовать boost :: ptr_vector <item> из Boost.PtrContainer.

Пример:

class Items {
private:
    struct item {
        unsigned int a, b, c;
    };
    std::vector<item> items;
}

if (items.size() > 5) // (just to ensure there is an element at that position)
    items.erase(items.begin() + 5); // no need to use operator delete at all

Чтобы удалить элемент, используйте:

удалить элементы [5];

после удаления элемента рекомендуется установить удаленный указатель на NULL, чтобы у вас не было ошибки, если вы позже удалите его снова по ошибке.

items [5] = NULL

Say I wanted to 'delete' an item, like so:

items[5] = NULL;

Я мало знаю Visual Basic, но это пахнет идиомой программирования Visual Basic, поскольку «Set a = None» (или Null, я не уверен) удалит объект, на который указывает a (или, скорее, уменьшит его счетчик ссылок для COM объекты).


Как заметил кто-то другой, вы должны использовать либо:

delete items[5];
items[5] = newContent;

или же:

delete items[5];
items[5] = NULL;

После delete[5] единственное возможное использование указателя, хранящегося в items[5], вызывает у вас проблемы. Что еще хуже, это может сработать вначале и начать давать сбои только тогда, когда вы выделяете что-то еще в пространстве, ранее использовавшемся *items[5]. Это причины, которые делают программирование на C / C++ «интересным», то есть действительно раздражающим (даже для тех, кто любит C, как я).

Запись только delete items[5]; спасает то, что может оказаться бесполезной записью, но это преждевременная оптимизация.

Для ясности: вы имеете в виду вызов «delete[]». Думаю, вы имеете в виду delete.

Я упоминаю об этом, потому что в C++ есть два отдельных оператора, operator delete и operator delete[]. Последний используется для удаления массивов объектов, выделенных с помощью operator new[], и применяется ли в этом случае нет. У вас есть массив объектов указатели на, которые вы должны инициализировать многократными вызовами operator new, а не одним вызовом operator new[].

Все, что я действительно пытаюсь сказать, это то, что вы используете delete[] запутанно и неоднозначно; смени его на delete.

Здесь есть несколько связанных вопросов:

  1. Согласно опубликованному вами коду, сам массив не выделяется в куче, если не struct, поэтому вам не нужно delete[] массив. Если вы создали массив с помощью new[], вам придется его delete[].
  2. Опубликованный код не говорит, как выделяются объекты, на которые указывают из массива. Если вы размещаете эти объекты в стеке, вы не должен удаляете их (опять же, это маловероятно, потому что ваши указатели станут недействительными, когда объекты, на которые они указывают, выпадают из области видимости). Если вы разместили их в куче (с новым), вы должен удаляете их, когда они выпадают из области видимости.
  3. Как уже предлагали другие, жизнь намного проще, если вы используете контейнер - особенно контейнер STL - и интеллектуальные указатели, что на данный момент означает указатели вне Boost.

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