Гарантирует ли удаление пустого указателя правильный размер?

Возможный дубликат:
Безопасно ли удалять пустой указатель?

Скажи у меня есть new распределение в класс под названием MyClass и распределение так же просто, как:

MyClass *myClassPtr = new MyClass();

И я храню ссылку на список void* где я просто говорю

myListOfPointers.add(static_cast<void*>(myClassPtr)); // this has to be void*

И позже я освобождаю память, вместо того чтобы делать:

delete myClassPtr

Я использую:

delete MyListOfPointer.get(0)

(Скажем, ссылка myClassPtr на нулевой индекс.) Также обратите внимание, что она должна быть void* так как этот список может хранить различные типы указателей, поэтому я не знаю тип указателя, который я удаляю:

Поэтому я не могу сделать что-то вроде:

delete static_cast<MyClass*>(MyListOfPointer.get(0))

Собирается ли таким образом освободить правильный объем памяти? (sizeof(MyClass))?

Замечания:
Я не ищу ответа, указывающего на умные указатели.

9

Решение

Удаление через void* приводит к неопределенному поведению, так что вам ничего не гарантировано.

5.3.5 Удалить [expr.delete]

1 Оператор delete-expression уничтожает наиболее производный объект (1.8) или массив, созданный новым выражением.
[…] Операнд должен иметь указатель на тип объекта или тип класса, имеющий одну неявную функцию преобразования (12.3.2) в указатель на тип объекта. Результат имеет тип void.78

78) Это означает, что объект нельзя удалить с помощью указателя типа void *, поскольку void не является типом объекта.

Акцент мой.


Поэтому, даже если вы сказали не говорить этого, ответ состоит в том, чтобы создать некую форму умного указателя. Необходимо было бы использовать стирание типа, чтобы скрыть тип внешне (позволяя разнородный список), но внутренне отследить тип, который он был задан, и то, как его удалить. Нечто подобное boost::any,

14

Другие решения

void Указатель не имеет информации о типе. Если MyClass есть деструктор, он не будет называться. Компилятор должен знать, что он удаляет, чтобы он мог генерировать соответствующий код. Если все ваши указатели в списке имеют одинаковый тип, то вы должны хранить этот тип в списке, а не как void, Если указатели имеют разные типы, но являются производными от общего базового типа, тогда присвойте этому базовому типу виртуальный конструктор и вместо этого сохраните указатели этого типа.

2

Не нужно использовать умный указатель, он просто умный.

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

class Holder {
public:
template <typename T>
explicit Holder(T const volatile* t):
_data(static_cast<void const volatile*>(t)),
_delete(&Delete<T>)
{}

void apply() { _deleter(_data); }

private:
typedef void (*Deleter)(void const volatile*);

template <typename T>
static void Delete(void const volatile* p) {
delete static_cast<T const volatile*>(p);
}

void const volatile* _data;
Deleter _deleter;
};

И сейчас:

std::list<Holder> owningList;

owningList.push_back(Holder(somePointer));

for (Holder& h: owningList) { h.apply(); }
1

Правильный ответ на этот вопрос, конечно, «нет»

Изменить: попросили предоставить больше информации, хотя я уже сделал это в комментарии к вопросу, удаление пустоты * не определено, и этот вопрос является еще одним способом задать этот: Безопасно ли удалять пустой указатель? — см. ответы там для деталей.

0
По вопросам рекламы [email protected]