2012-09-07 17 views
12

Pregunta simple aquí: ¿se le permite eliminar explícitamente un boost::shared_ptr usted mismo? ¿Deberías alguna vez?Eliminación explícita de un shared_ptr

Aclaración, no me refiero a eliminar el puntero que tiene el shared_ptr. Me refería al propio shared_ptr. Sé que la mayoría de la gente sugiere no hacerlo, así que me preguntaba si está bien hacerlo explícitamente.

+1

Ciertamente se le permite eliminar una (asignada dinámicamente) * shared_ptr *; borrar su contenido es una pregunta completamente diferente ;-) –

+0

Creo que está buscando 'weak_ptr'. – ybungalobill

+5

La asignación dinámica de un 'shared_ptr' anula el propósito de utilizar' shared_ptr'. – Dan

Respuesta

2

No puede forzar su cuenta de referencia a cero, no.

Piensa qué se necesitaría para que funcione. Debería ir a cada lugar donde se utiliza shared_ptr y borrarlo.

Si forzó el puntero compartido para eliminar y establecerlo en NULL, sería como un weak_ptr. Sin embargo, todos los lugares del código que utilizan ese shared_ptr no están listos para eso y esperan tener un puntero válido. No tienen ninguna razón para verificar NULL, y esos pedazos de código se bloquearían.

23

Tu pregunta no está clara. Si ha asignado un shared_ptr dinámicamente, entonces ciertamente puede delete cuando lo desee.

Pero si está preguntando si puede eliminar cualquier objeto que esté siendo administrado por shared_ptr, entonces la respuesta es ... depende. Si shared_ptr::unique devuelve verdadero, entonces llamar al shared_ptr::reset eliminará el objeto administrado. Sin embargo, si shared_ptr::unique devuelve falso, significa que hay más de un shared_ptr compartiendo la propiedad de ese objeto. En este caso, una llamada al reset solo dará como resultado que el recuento de referencia disminuya en 1, la eliminación real del objeto tendrá lugar cuando el último shared_ptr que administre ese objeto salga fuera del alcance o sea él mismo reset.

EDIT:
Después de su edición, parece que está preguntando por la eliminación de un shared_ptr asignado dinámicamente. Algo como esto:

auto sp = new boost::shared_ptr<int>(new int(42)); 

// do something with sp 

delete sp; 

Esto está permitido y funcionará como se esperaba, aunque sería un caso de uso inusual. La única advertencia es que si entre la asignación y eliminación de sp crea otro shared_ptr que comparte la propiedad del objeto, eliminar sp no dará como resultado la eliminación del objeto, eso solo ocurrirá cuando el recuento de referencias para el objeto vaya a 0

4

[Editar: puede delete a shared_ptr si y solo si se creó con new, al igual que cualquier otro tipo. No puedo pensar por qué te gustaría crear un shared_ptr con new, pero no hay nada que nos impida.]

Bueno, usted podría escribir delete ptr.get();.

Si lo hace, casi inevitablemente conduce a un comportamiento indefinido o bien cuando los otros propietarios compartidos usan su shared_ptr para acceder al objeto ahora suprimido, o el último shared_ptr al objeto es destruido, y el objeto se elimina de nuevo.

Así que no, no deberías.

El propósito de shared_ptr es administrar un objeto que ninguna "persona" tiene el derecho o la responsabilidad de eliminar, ya que podría haber otros que comparten la propiedad. Entonces tampoco deberías quererlo nunca.

1

Si desea simular el decremento recuento, puede hacerlo de forma manual en el montón, así:

int main(void) { 
    std::shared_ptr<std::string>* sp = new std::shared_ptr<std::string>(std::make_shared<std::string>(std::string("test"))); 
    std::shared_ptr<std::string>* sp2 = new std::shared_ptr<std::string>(*sp); 
    delete sp; 

    std::cout << *(*sp2) << std::endl; // test 
    return 0; 
} 

O en la pila usando std::shared_ptr::reset() así:

int main(void) { 
    std::shared_ptr<std::string> p = std::make_shared<std::string>(std::string("test")); 
    std::shared_ptr<std::string> p2 = p; 
    p.reset(); 

    std::cout << *p2 << std::endl; // test 
    return 0; 
} 

Pero no es eso es útil

0

La eliminación manual es útil en algunos (¿muy?) Raros casos.

¡Además de eliminar explícitamente, a veces TIENE que destruir explícitamente un puntero compartido cuando lo "borra"!

Las cosas pueden ponerse raras cuando interactúan con el código C, pasando un shared_ptr como un valor opaco.

Por ejemplo I tiene la siguiente para el paso de objetos desde y hacia el lenguaje de script Lua que está escrito en C. (www.lua.org)

static void push(lua_State *L, std::shared_ptr<T> sp) 
{ 
    if(sp == nullptr) { 
     lua_pushnil(L); 
     return; 
    } 

    // This is basically malloc from C++ point of view. 
    void *ud = lua_newuserdata(L, sizeof(std::shared_ptr<T>)); 

    // Copy constructor, bumps ref count. 
    new(ud) std::shared_ptr<T>(sp); 

    luaL_setmetatable(L, B::class_name); 
} 

así que eso es un shared_ptr en parte de la memoria malloc'd . El reverso es este ... (la configuración se llamará justo antes de que la basura de Lua recolecte un objeto y 'lo libere').

static int destroy(lua_State *L) 
{ 
    // Grab opaque pointer 
    void* ud = luaL_checkudata(L, 1, B::class_name); 

    std::shared_ptr<T> *sp = static_cast<std::shared_ptr<T>*>(ud); 

    // Explicitly called, as this was 'placement new'd 
    // Decrements the ref count 
    sp->~shared_ptr(); 

    return 0; 
}