Інші вже вирішували інші проблеми, тому я просто погляну на один момент: чи хочете ви коли-небудь видалити об'єкт вручну.
Відповідь - так. @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, у будь-якому випадку).