Зачем вам писать что-то подобное? (намеренно не используя delete [] в массиве)

Я иногда сталкивался с подобным кодом - я подозреваю, что создатель/боялся, что удаление таблицы приведет к переходу по таблице и "эффективности затрат" (что imho не будет сделано в любом случае)... есть ли какая-либо реальная выгода, которую можно получить/рассмотреть/представить из-за того, что здесь не используется таблица delete?

myClass** table = new myClass* [size];
... //some code that does not reallocate or change the value of the table pointer ;)
delete table; // no [] intentionally

Ответы

Ответ 1

На самом деле нет причин писать так и серьезную причину, чтобы никогда этого не делать.

Верно, что для типов с тривиальными деструкторами (например, для raw-указателей в вашем случае) нет необходимости знать фактическое количество элементов в массиве, и поэтому компилятор может решить сопоставить новые [] и удалить [] на новые и delete, чтобы уменьшить накладные расходы. Если он решит таким образом, вы не сможете остановить его без дополнительных шагов, поэтому оптимизация компилятора будет проходить без вашего уведомления и будет бесплатной.

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

Добавьте к этому, что эта оптимизация, зависящая от компилятора, не переносима.

Итак, это так, когда вы не получаете никаких преимуществ, вытесняя delete [] с удалением, но рискуете большим временем, полагаясь на поведение undefined.

Ответ 2

Если вы это сделаете, вы получите то, что С++ Standard вызывает поведение undefined - все может произойти.

Ответ 3

Это утечка памяти. A new [] следует сопоставить с помощью delete []. Кроме того, поскольку table является указателем на первый элемент массива указателей, любой член массива, если он сам по себе должен быть выделен с помощью delete [].

Ответ 4

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

Ответ 5

Это определенно неверно, так как s new [] должен быть сопряжен с delete []. Если вы этого не сделаете, вы получите поведение undefined.

Он может работать (частично), потому что большинство реализаций используют новые для реализации новых []. Единственная разница для такой реализации заключалась бы в том, что она вызывала бы только один деструктор (для первого элемента вместо всех деструкторов, но избегайте его, поскольку он не легальный С++.

Ответ 6

В теории вы должны вызвать delete [].

EDIT: Следующее относится только к Microsoft Visual С++ (я должен был сказать это).

На практике в Microsoft Visual С++ не имеет значения, какое удаление вы используете, если объекты в массиве не имеют деструкторов. Поскольку у вас есть массив указателей, а указатели не могут иметь деструкторы, вы должны быть в порядке.

Однако, как указывали другие, неверно С++ смешивать новые [] и удалять без []. Хотя в этом случае он может работать на Visual С++, код не переносится и может быть неудачным в других компиляторах.

Но вернемся к конкретному случаю Visual С++, даже если вы вызываете delete [], компилятор поймет, что ему не нужно перебирать массив, вызывающий деструкторы, когда он представляет собой массив примитивных типов, таких как int, char или указатели. Вызов delete в этом случае фактически работает и ничего не сломает. Было бы медленнее делать правильные вещи и вызывать delete [], но это также не будет быстрее.

Фактически, в MSVС++ delete [] p сразу вызывает обычный оператор delete (void * p), когда p является указателем на простой тип или без деструкторов.

Те, кто мне не верит, выполните этот код в код CRT для первых двух вызовов для удаления [].

#include "stdafx.h"
#include <malloc.h>
#include <iostream>
using namespace std;

class NoDestructor
{
    int m_i;
};

class WithDestructor
{
public:
    ~WithDestructor()
    {
        cout << "deleted one WithDestructor at " << (void *) this<< endl;
    }
};

int _tmain(int argc, _TCHAR* argv[])
{
    int **p = new int *[20];
    delete [] p;

    p = (int**) malloc(80);
    free(p);

    NoDestructor *pa = new NoDestructor[20];
    delete [] pa;

    WithDestructor *pb = new WithDestructor[20];
    delete [] pb;

    return 0;
}

Ответ 7

этот оператор оставит все объекты myClass, на которые указывают все указатели в массиве, висящем в памяти. Он также оставляет массив указателей в памяти. Нет никакого способа, который может быть полезен, поскольку он освобождает только 32 бит памяти, а ОС по-прежнему считает, что у вас есть (размер) myClasses и указатели для каждого используемого. Это просто пример программиста, который не очищается после себя должным образом.

Ответ 8

Обратитесь к разделу [16.11] "Как мне выделить/нераспределить массив вещей?" и далее в С++ FAQ Lite,

http://www.parashift.com/c++-faq-lite/freestore-mgmt.html#faq-16.11

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

Инстанс myClass, на который указывают элементы вашего массива, также должен быть удален там, где они созданы.