Причина, почему бы не иметь макрос DELETE для С++

Существуют ли какие-либо веские причины (кроме "макросов являются злыми", возможно) НЕ использовать следующие макросы?

#define DELETE( ptr ) \
if (ptr != NULL)      \
{                     \
    delete ptr;       \
    ptr = NULL;       \
}

#define DELETE_TABLE( ptr ) \
if (ptr != NULL)            \
{                           \
    delete[] ptr;           \
    ptr = NULL;             \
}

Ответ 1

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

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

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

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

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

Ответ 2

Потому что это фактически не решает много проблем.

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

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

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

Ответ 3

Потому что это нормально, чтобы удалить указатель 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; в перегруженном delete, вы фактически устанавливаете local один, но не оригинальный p. В принципе, мы получаем копию указателя в перегруженном delete.

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

Ответ 4

Поскольку DELETE уже определен в winnt.h:

#define DELETE (0x00010000L)

Ответ 5

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

Ответ 6

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

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

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

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

Ответ 7

  • Удаление нулевого указателя ничего не делает, поэтому нет необходимости проверять, является ли указатель нулевым до удаления. Нулевое удаление удалённого указателя может потребоваться (но не во всех случаях).

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

  • Удаление указателя, который не был динамически назначен новым, все равно будет проблемой...

Ответ 8

  • Макросы являются злыми. Почему бы не использовать встроенный шаблонные функции?
  • Вы можете удалить null ptrs.
  • Во многих случаях вы не необходимо установить ptr в null - деструкторы, например.

Ответ 9

  • макросы являются злыми: p Серьезно рассмотрите возможность использования встроенных template функций вместо
  • установка указателя на NULL после освобождения имеет тенденцию маскировать ошибки
  • рекомендует if (ptr != NULL) проверять как механизм управления потоком. Лично я считаю этот код запах по линиям void foo(int arg) заменяется на void foo(int arg, bool doAdvancedThings=false)
  • поощряет использование необработанных указателей в памяти, которые необходимо удалить - shared_ptr и его родственники должны всегда использоваться для владения, необработанные указатели могут использоваться для другой доступ
  • поощряет просмотр переменной указателя после освобождения, еще хуже используя if (ptr != NULL) вместо if (ptr)... сравнение указателей - это еще один запах кода

Ответ 11

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

Ответ 12

  • Это не дает вам большой пользы. Удаление нулевого указателя безвредно, поэтому единственное преимущество - установить указатель на NULL после удаления. Если разработчик может забыть называть ваш макрос, а не удалять, она также может забыть об отключении указателя, поэтому вы не защищаете себя от небрежного разработчика. Единственное преимущество в том, что это происходит в двух строках, а не в одном.
  • Это потенциально сбивает с толку. delete - стандартная часть языка. Ваша макро или шаблонная функция отсутствует. Таким образом, новому разработчику необходимо будет найти определение макроса, чтобы понять, что делает ваш код.

По моему мнению, преимущество не перевешивает стоимость.