Другие уже рассмотрели другие проблемы, поэтому я просто остановлюсь на одном моменте: вы когда-нибудь хотели удалить объект вручную.
Ответ положительный. @DavidSchwartz привел один пример, но он довольно необычный. Я приведу пример, который находится под капотом того, что многие программисты на C ++ используют все время: std::vector(и std::dequeхотя он используется не так часто).
Как известно большинству людей, std::vectorбудет выделять больший блок памяти, когда / если вы добавляете больше элементов, чем может вместить его текущее распределение. Однако, когда он это делает, у него есть блок памяти, способный хранить больше объектов, чем сейчас в векторе.
Чтобы управлять этим, то, что vectorскрывается, выделяет необработанную память через Allocatorобъект (что, если не указано иное, означает, что он использует ::operator new). Затем, когда вы используете (например), push_backчтобы добавить элемент в vector, внутри вектор использует a placement newдля создания элемента в (ранее) неиспользованной части его пространства памяти.
Теперь, что происходит, когда / если вы eraseполучаете элемент из вектора? Он не может просто использовать delete- это освободит весь его блок памяти; ему необходимо уничтожить один объект в этой памяти, не разрушая другие, или освобождая какой-либо блок памяти, который он контролирует (например, если у вас erase5 элементов из вектора, а затем сразу еще push_back5 элементов, гарантируется, что вектор не будет перераспределен память, когда вы это сделаете.
Для этого вектор напрямую уничтожает объекты в памяти, явно вызывая деструктор, а не используя delete.
Если, возможно, кто-то другой должен был написать контейнер, использующий непрерывное хранилище, примерно как это vectorделает (или какой-то его вариант, как на std::dequeсамом деле), вы почти наверняка захотите использовать тот же метод.
Например, давайте рассмотрим, как можно написать код для кольцевого буфера.
#ifndef CBUFFER_H_INC
#define CBUFFER_H_INC
template <class T>
class circular_buffer {
T *data;
unsigned read_pos;
unsigned write_pos;
unsigned in_use;
const unsigned capacity;
public:
circular_buffer(unsigned size) :
data((T *)operator new(size * sizeof(T))),
read_pos(0),
write_pos(0),
in_use(0),
capacity(size)
{}
void push(T const &t) {
// ensure there's room in buffer:
if (in_use == capacity)
pop();
// construct copy of object in-place into buffer
new(&data[write_pos++]) T(t);
// keep pointer in bounds.
write_pos %= capacity;
++in_use;
}
// return oldest object in queue:
T front() {
return data[read_pos];
}
// remove oldest object from queue:
void pop() {
// destroy the object:
data[read_pos++].~T();
// keep pointer in bounds.
read_pos %= capacity;
--in_use;
}
~circular_buffer() {
// first destroy any content
while (in_use != 0)
pop();
// then release the buffer.
operator delete(data);
}
};
#endif
В отличие от стандартных контейнеров, здесь используется operator newи operator deleteнапрямую. Для реального использования вы, вероятно, захотите использовать класс распределителя, но на данный момент он будет больше отвлекать, чем способствовать (во всяком случае, IMO).