2010-10-13 16 views
5

Estoy usando C++. C++ 0x con Visual Studio 2010 para ser correcto.¿Cómo se comportan los punteros inteligentes no intrusivos con respecto a la herencia y la herencia múltiple?

Supongamos que tengo una clase Z. Para que sea más seguro en mi aplicación trabajar con punteros a esta clase, puedo usar punteros inteligentes (puntero compartido, puntero débil).

Ahora esta clase Z hereda de una clase X. Algunas partes de mi solicitud trabajarán con punteros a la clase X, otros trabajarán con punteros a clase Z.

  • ¿Puedo utilizar punteros inteligentes?
  • ¿Los punteros compartidos aún funcionan si tengo alguno que se refiera a X y a otros que se refieran a Z? ¿Se garantiza que la destrucción del último puntero compartido a la instancia (independientemente de si es std::shared_ptr<X> o std::shared_ptr<Z>) elimina la instancia? ¿Estoy seguro de que si borro std::shared_ptr<X>, la instancia se conservará mientras haya otra std::shared_ptr<Y>?

Ahora supongamos que utilizo la herencia múltiple, en el que Z hereda de clases X e Y. Algunas partes de mi aplicación funcionará con std::shared_ptr<X>, otros con std::shared_ptr<Y> y otros con std::shared_ptr<Z>.

  • ¿Puedo seguir utilizando punteros compartidos de esta manera?
  • ¿Todavía se garantiza que solo el último puntero inteligente (independientemente de si apunta a X, Y o Z) elimina la instancia?

Por cierto, ¿cómo puedo lanzar con seguridad un puntero inteligente a otro, p. emitir std::shared_ptr<Z> a std::shared_ptr<X>? ¿Esto funciona? Está permitido?

Observe que me refiero explícitamente a punteros no intrusivos (como el nuevo std::shared_ptr y std::weak_ptr en C++ 0x). Al usar punteros intrusivos (como en Boost), probablemente funcione ya que la instancia en sí es responsable de mantener el contador.

Respuesta

6

Sí esto es compatible con la norma, §20.9.11.2.10 [util.smartptr.shared.cast].

Las utilidades que necesita son:

  • std::static_pointer_cast<>()
  • std::dynamic_pointer_cast<>()

Ellos tienen la misma semántica que sus C++ 03 piezas contrarias static_cast<>() y dynamic_cast<>(). La única diferencia es que solo funcionan en std::shared_ptr s. Y solo para verboso, hacen lo que esperan y comparten correctamente el recuento de referencias entre el original y el nuevo elenco shared_ptr s.

struct X { virtual ~X(){} }; 
struct Y : public X {}; 
struct Z : public X {}; 

int main() 
{ 
    { 
     //C++03 
     X* x = new Z; 
     Z* z = dynamic_cast<Z*>(x); 
     assert(z); 
     x = new Y; 
     z = dynamic_cast<Z*>(x); 
     assert(!z); 
     z = static_cast<Z*>(x); 
     assert(z); //EVIL!!! 
    } 

    { 
     //C++0x 
     std::shared_ptr<X> x{new Z}; 
     std::shared_ptr<Z> z{std::dynamic_pointer_cast<Z>(x)}; 
     assert(z); 
     x = std::make_shared<Y>(); 
     z = std::dynamic_pointer_cast<Z>(x); 
     assert(!z); 
     z = std::static_pointer_cast<Z>(x); 
     assert(z); //EVIL!!! 

     // reference counts work as expected. 
     std::shared_ptr<Y> y{std::static_pointer_cast<Y>(x)}; 
     assert(y); 

     std::weak_ptr<Y> w{y}; 
     assert(w.expired()); 

     y.reset(); 
     assert(w.expired()); 

     x.reset(); 
     assert(!w.expired());  
    } 
    { 
     //s'more nice shared_ptr features 
     auto z = std::make_shared<X>(); 
     std::shared_ptr<X> x{z}; 
     assert(z == x); 
     x = z; //assignment also works. 
    } 
} 
+0

Wow nunca oído hablar de este ... O__O No se hace referencia a esto en cualquier recurso que pude encontrar en C++ 0x que no sea el (indigest) proyecto ... – Klaim

+0

No sabía a ciencia cierta los moldes donde estaba hasta que lo busqué. Sin embargo, sospeché fuertemente que estaban allí ya que formaban parte de la biblioteca Boost.Smartptr original. –

+0

Deshágase de "std ::" delante de los operadores de conversión incorporados.Además, un modelo dinámico de este tipo requiere clases polimórficas. Tus clases de ejemplo no son polimórficas. – sellibitze

Cuestiones relacionadas