Otros ya han solucionado los otros problemas, así que solo veré un punto: ¿alguna vez deseas eliminar un objeto manualmente?
La respuesta es sí. @DavidSchwartz dio un ejemplo, pero es bastante inusual. Daré un ejemplo que está debajo del capó de lo que muchos programadores de C++ usan todo el tiempo: std::vector
(y std::deque
, aunque no se usa tanto).
Como la mayoría de la gente sabe, std::vector
asignará un bloque de memoria más grande cuando/si agrega más elementos de los que puede contener su asignación actual. Sin embargo, cuando hace esto, tiene un bloque de memoria que puede contener más objetos que los que están actualmente en el vector.
para gestionar dicho, lo que hace vector
bajo las sábanas es asignar prima de memoria a través de laAllocator
objeto (que, a menos que se especifique lo contrario, significa que utiliza ::operator new
). Luego, cuando usa (por ejemplo) push_back
para agregar un elemento al vector
, internamente el vector usa un placement new
para crear un elemento en la parte (previamente) no utilizada de su espacio de memoria.
Ahora, ¿qué sucede cuando/si erase
un elemento del vector? No puede simplemente usar delete
, que liberaría todo su bloque de memoria; necesita destruir un objeto en esa memoria sin destruir ningún otro, o liberar cualquier bloque de memoria que controle (por ejemplo, si erase
5 elementos de un vector, inmediatamente push_back
5 elementos más, es garantizado que el vector se no memoria reallocate cuando hacerlo.
Para ello, el vector destruye directamente los objetos en la memoria mediante una llamada explícita al destructor, no utilizando delete
.
Si, por ventura, alguien más debía escribir un contenedor usando almacenamiento contiguo aproximadamente como un vector
(o alguna variante de eso, como std::deque
realmente lo hace), casi seguramente querrás utilizar la misma técnica.
Solo por ejemplo, consideremos cómo podría escribir el código para un anillo de memoria circular.
#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;
}
// release the buffer:
~circular_buffer() { operator delete(data); }
};
#endif
A diferencia de los contenedores estándar, este utiliza operator new
y operator delete
directamente. Para uso real, es probable que desee utilizar una clase de asignador, pero por el momento haría más para distraer que contribuir (IMO, de todos modos).
Incluso sus preguntas específicas son demasiado amplias. "Ese puntero se borra más tarde" y "se le da una nueva dirección para señalar" son bastante diferentes. Busque más (algunos de ellos han sido respondidos), y luego haga preguntas separadas para las partes que no pudo encontrar. –