Причина, почему не иметь УДАЛИТЬ макрос для C++

Доверие - Простой и простой. Правительство не может открыть себя ни для кого изменение, это - код.

, Например: кодер мог сознательно ввести переполнение буфера в ядро Linux. Они знают, что это - местоположение, требуемая полезная нагрузка и моментальный компромисс удара. Это также предлагает отрицание наличия, как это появляется как "просто другая" ошибка переполнения.

Редактирование - Мое опровержение к комментариям: http://www.debian.org/News/2006/20060713

debian ядро поставилось под угрозу через поставивший под угрозу хост. Да, код может быть рассмотрен, но мы все еще определяем новые ошибки даже после 20 лет знания, что переполнение буфера является проблемой.

Обзор не является идеальным вместилищем.

17
задан Sam 10 August 2014 в 15:56
поделиться

12 ответов

Лично я предпочитаю следующие

template< class T > void SafeDelete( T*& pVal )
{
    delete pVal;
    pVal = NULL;
}

template< class T > void SafeDeleteArray( T*& pVal )
{
    delete[] pVal;
    pVal = NULL;
}

. Они компилируются ТОЧНО в один и тот же код в конце.

Может быть какой-то странный способ сломать систему #define, но лично ( И я, наверное, застону от этого;) Я не думаю, что это большая проблема.

42
ответ дан 30 November 2019 в 09:56
поделиться

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


Похоже, я ошибался насчет второго пункта:

Если вы хотите установить указатель на NULL, после удаления вы можете перегрузить оператор delete глобально

Дело в том, что если вы перегрузите глобальные new и delete , у вас может получиться что-то вроде этого:

void* operator new(size_t size)
{
    void* ptr = malloc(size);

    if(ptr != 0)
    {
        return ptr;
    }

    throw std::bad_alloc("Sorry, the allocation didn't go well!");
}

void operator delete(void* p)
{
    free(p);
    p = 0;
}

Теперь, если вы установите p = 0 ; в перегруженном удалении , вы фактически устанавливаете локальный , но не исходный p . По сути, мы получаем копию указателя в перегруженном delete .

Извините, это было в моей голове, я подумал об этом. В любом случае, я бы написал встроенную функцию шаблона, чтобы сделать это, вместо того, чтобы писать ЗЛОЕ МАКРОСЫ :)

16
ответ дан 30 November 2019 в 09:56
поделиться
  • delete принимает указатель NULL без проблем, поэтому тесты излишни.
  • сброс указателя на NULL не всегда возможен, поэтому их нельзя использовать систематически.
  • безопасность, которую они приносят, иллюзорна: по моему опыту, большинство проблем с висячими указателями возникает из-за указателей, отличных от того, который используется для удаления.
9
ответ дан 30 November 2019 в 09:56
поделиться
  1. удаление нулевого указателя ничего не делает, поэтому перед удалением нет необходимости проверять, является ли указатель нулевым. Обнуление удаленного указателя все еще может потребоваться (но не в каждом случае).

  2. Следует избегать макросов, насколько это возможно, поскольку их сложно отлаживать, поддерживать, вызывать возможные побочные эффекты, они не являются частью пространств имен и т. Д. .

  3. удаление указателя, который не был динамически выделен с помощью new, по-прежнему будет проблемой ...

3
ответ дан 30 November 2019 в 09:56
поделиться

Ваш макрос не работает по нескольким причинам:

  • Это макрос. Он не соблюдает правила области видимости или ряд других языковых функций, что упрощает его неправильное использование.
  • Это может вызвать ошибки компиляции: DELETE (getPtr ()); не будет компилироваться, потому что вы не можете установить для вызова функции значение null. Или, если указатель является константным, ваш макрос также не сработает.
  • Он ничего не дает. delete NULL разрешено стандартом.

Наконец, как сказал гримнер, вы пытаетесь решить проблему, которой изначально не должно быть. Почему вы вообще вручную вызываете delete? `Разве вы не используете стандартные библиотечные контейнеры? Умные указатели? Распределение стека? RAII?

Как сказал ранее Страуструп, единственный способ избежать утечек памяти - это избежать вызова delete.

5
ответ дан 30 November 2019 в 09:56
поделиться
  1. Макросы злы. Почему бы не использовать встроенный шаблонные функции?
  2. Вы можете удалить null ptrs.
  3. Во многих случаях вы не нужно установить для ptr значение null - деструкторы, например.
3
ответ дан 30 November 2019 в 09:56
поделиться
  1. макросы злы : p Серьезно, подумайте об использовании встроенных шаблонных функций вместо этого
  2. установка указателя на NULL после освобождения имеет тенденцию маскировать ошибки
  3. поощряет проверку if (ptr! = NULL) в качестве механизма управления потоком. Лично я считаю запах кода похож на void foo (int arg) , заменяемый на void foo (int arg, bool doAdvancedThings = false)
  4. поощряет использование необработанных указателей на память, которую необходимо удалить - shared_ptr и его родственники должны всегда использоваться для владения, необработанные указатели могут использоваться для другой доступ
  5. поощряет просмотр переменной-указателя после освобождения, что еще хуже при использовании if (ptr! = NULL) вместо if (ptr) ... сравнение указателей - это еще один запах кода
3
ответ дан 30 November 2019 в 09:56
поделиться

Да, вы никогда не должны вызывать удаление напрямую. Используйте shared_ptr, scoped_ptr, unique_ptr или любой другой умный указатель, который есть в вашем проекте.

2
ответ дан 30 November 2019 в 09:56
поделиться

Потому что на самом деле он не решает многих проблем.

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

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

С точки зрения дизайна вызов вручную delete или delete [] должен происходить относительно редко. Использование объектов по значению вместо динамически выделяемых объектов там, где это необходимо; m использование std :: vector вместо динамически выделяемых массивов и перенос владения объектами, которые должны быть динамически выделены, в соответствующий интеллектуальный указатель (например, auto_ptr , scoped_ptr или shared_ptr ) для управления их сроком службы - все это подходы к проектированию, которые делают замену delete и delete [] на «более безопасный» макрос - подход со сравнительно низкой выгодой.

30
ответ дан 30 November 2019 в 09:56
поделиться

Потому что DELETE уже определено в winnt.h:

#define DELETE (0x00010000L)

13
ответ дан 30 November 2019 в 09:56
поделиться

Вместо этого используйте boost :: shared_ptr <>.

http://www.boost.org/doc/libs/1_39_0/libs/smart_ptr/shared_ptr.htm

МАКРОС здесь предоставляет некоторые функции, которые вы вероятно ищете.

3
ответ дан 30 November 2019 в 09:56
поделиться
  1. Это не дает вам особой пользы. Удаление нулевого указателя безвредно, поэтому единственное преимущество - установка указателя на NULL после удаления. Если разработчик может не забыть вызвать ваш макрос, а не удалить, он также может не забыть обнулить указатель, чтобы вы не защищали себя от небрежного разработчика. Единственное преимущество состоит в том, что это происходит в двух строках, а не в одной.
  2. Это потенциально сбивает с толку. удаление - это стандартная часть языка. Ваш макрос или шаблонная функция - нет. Так что новому разработчику нужно будет найти это определение макроса, чтобы понять, что делает ваш код.

По моему мнению, выгода не перевешивает затраты.

2
ответ дан 30 November 2019 в 09:56
поделиться
Другие вопросы по тегам:

Похожие вопросы: