2011-03-23 6 views
7

ya hay un par de preguntas sobre este tema, pero todavía no estoy seguro de qué hacer: nuestra base de código usa shared_ptr en muchos lugares. Tengo que admitir que no definimos la propiedad claramente al escribirla.¿Debo convertir shared_ptr en weak_ptr cuando se pasa a un método?

Tenemos algunos métodos como

void doSomething(shared_ptr<MyClass> ptr) 
{ 
     //doSomething() is a member function of a class, but usually won't store the ptr 
     ptr->foo(); 
     ... 
} 

Después de haber descubierto los primeros (indirectos) dependencias circulares que me gustaría corregir los errores en nuestro diseño. Pero no estoy exactamente seguro de cómo. ¿Hay algún beneficio en cambiar el método de arriba a

void doSomething(weak_ptr<MyClass> ptr) 
{ 
     shared_ptr<MyClass> ptrShared = ptr.lock(); 
     ptrShared->foo(); 
     ... 
} 

?

También estoy confundido porque algunas personas dicen (incluida la Guía de estilo de Google) que en primer lugar es importante obtener la propiedad correcta (lo que probablemente significaría la introducción de muchos weak_ptrs, por ejemplo en el ejemplo con los métodos anteriores, pero también para muchas variables miembro que tenemos). Otros dicen (ver enlaces a continuación) que debe usar weak_ptr para romper dependencias cíclicas. Sin embargo, detectarlos no siempre es fácil, entonces me pregunto si realmente debería usar shared_ptr hasta que me encuentre con problemas (y me dé cuenta de ellos), y luego los solucione.

Gracias por su opinión!

Ver también

+0

Sería shared_ptr & ptr ser mejor? – DanDan

+1

"detectarlos no siempre es fácil" - entonces realmente necesita agregar más pasos a su proceso de diseño. Líneas claras y oscuras en sus diagramas de relación de clase, o lo que sea necesario. También puede considerar romper ciclos con punteros crudos en lugar de punteros débiles, para la mayoría de las relaciones asimétricas donde el "propietario" nunca será destruido antes que todos los "no propietarios". –

+1

@DanDan: No lo creo, consulte http://stackoverflow.com/questions/327573/c-passing-references-to-boostshared-ptr – Philipp

Respuesta

6

No hemos definir claramente la propiedad.

Debe definir claramente a quién pertenece qué. No hay otra manera de resolver esto. Cambiar arbitrariamente algunos usos de shared_ptr con weak_ptr no hará las cosas mejor.

+0

bien, creo que esto no debería ser demasiado difícil ya que el diseño es (aún no :-)) demasiado malo, supongo. Sin embargo, la pregunta sigue siendo: ¿debo introducir weak_ptrs solo donde detecte círculos (si hay más) o en cualquier lugar donde el objeto/método no tenga propiedad? – Philipp

+1

@Phillip - Si observa el ejemplo que dio, no hay diferencia en el comportamiento entre pasar un weak_ptr y un shared_ptr. Para usar el weak_ptr, primero debe crear un shared_ptr desde él, que en realidad es lo mismo que haber pasado un shared_ptr en primer lugar. – Nathanael

2

Algunas personas tienen razón: al principio debe tener una idea muy clara de la propiedad de los objetos en su proyecto.

shared_ptrs son shared, por ej. "Owned by community". Eso podría o no ser deseable. Así que aconsejaría definir el modelo de propiedad y luego no abusar de semántica shared_ptr y usar punteros simples cuando la propiedad no deba ser "compartida" más.

El uso de weak_ptrs enmascararía más el problema en lugar de solucionarlo.

4

No hay ningún beneficio en cambiar su diseño anterior de shared_ptr a weak_ptr. Obtener la propiedad correcta no se trata de usar weak_ptrs, se trata de administrar quién almacena el shared_ptr por un período de tiempo significativo. Si paso un shared_ptr a un método, suponiendo que no almaceno ese shared_ptr en un campo en mi objeto como parte de ese método, no he cambiado quién posee esos datos.

En mi experiencia, la única razón para usar weak_ptr es cuando absolutamente debe tener un ciclo de punteros y necesita romper ese ciclo. Pero primero debes considerar si puedes modificar tu diseño para eliminar el ciclo.

Normalmente desaconsejo mezclar shared_ptr y punteros sin formato. Inevitablemente sucede (aunque probablemente no debería) que un puntero sin formato debe pasarse a una función que toma un shared_ptr de ese tipo. Un weak_ptr se puede convertir de forma segura a un shared_ptr, con un puntero sin formato no tiene suerte. Peor aún, un desarrollador sin experiencia con shared_ptr's puede crear un nuevo shared_ptr desde ese puntero sin formato y pasarlo a la función, lo que hace que ese puntero se elimine cuando la función retorna. (De hecho, tuve que corregir este error en el código de producción, así que sí sucede :))

+0

"Inevitablemente ocurre_ (...)" Esta explicación es una de las pocas justificaciones articuladas para 'weak_ptr' que he visto en SO (o en otro lugar). Gracias. – curiousguy

3

Parece que tiene un problema de diseño. shared_ptr proporciona una implementación fácil de usar para soluciones de diseño específicas, pero (ni nada) puede reemplazar el diseño. Hasta que haya determinado la duración real de cada tipo de objeto , no debe utilizar shared_ptr. Una vez que haya hecho , la mayoría de los problemas shared_ptr/weak_ptr desaparecerán.

Si, una vez hecho esto, y determinó que el tiempo de vida de algunos objetos no depende de la de otros objetos, y hay ciclos en esta dependencia, usted tiene que determinar (a nivel de diseño , otra vez) cómo para administrar esos ciclos --- es muy posible, por ejemplo, que en esos casos, shared_ptr no es la solución correcta , o que muchos de los indicadores involucrados son solo para la navegación , y deben ser punteros sin formato.

En cualquier caso, la respuesta a su pregunta reside en el nivel de diseño . Si tiene que preguntarlo al codificar, entonces es hora de ir al diseño .

Cuestiones relacionadas