2010-12-16 5 views

Respuesta

10

Creo que esto es un problema de encapsulamiento. Si una biblioteca externa utiliza referencias débiles internamente, no se debe esperar que mi código sepa de antemano que cuando hago una copia de una referencia, puede que desaparezca repentinamente. La expectativa habitual en Perl es que una referencia seguirá siendo válida mientras exista. Cuando llamas al weaken, básicamente has prometido que tomarás los pasos necesarios para verificar que la referencia aún sea válida antes de usarla.

Como una segunda razón, la interfaz para debilitar una copia fuerte de una referencia débil es bastante directa.

my $new_ref = $old_ref; if (isweak($old_ref)) { weaken($new_ref); } 

El código para hacer lo mismo para obtener una buena referencia si una referencia débil crea una referencia débil es un poco más complicado.

my $new_ref; 
if (ref($old_ref) eq 'ARRAY') { 
    $new_ref = \@{$old_ref}; 
} 
elsif (ref($old_ref) eq 'HASH') { 
    $new_ref = \%{$old_ref}; 
} 
elsif (..... 

Si ya conoce la ref sólo puede haber un tipo que puede ahorrar la cascada if/elsif y simplemente hacer lo DEREF-reref, pero todavía es más difícil juzgar por qué sin referencia que acaba de tomar una nueva referencia. El próximo mantenedor intentará 'arreglar' tu código.

3

no estoy seguro de por qué esto es el comportamiento por defecto, pero aquí es la solución basada en el código de la documentación Scalar::Util:

$ref = \$foo; 
$weak = isweak($ref);    # false 
weaken($ref); 
$weak = isweak($ref);    # true 

# copying a weak reference creates a new strong one 
$copy = $ref; 
$weak = isweak($copy);    # false 

# the solution is simply to weaken the copy 
$weaken($copy); 
$weak = isweak($copy);    # true 

Si quisiera hacer una subrutina que tomó una referencia débil como argumento y devolvió una copia debilitada de esa referencia, que sería fácil usando el código que se muestra arriba.

+0

... ¿está seguro de que una subrutina puede devolver una referencia débil?Me parece que cualquier referencia debilitada creada dentro de una subrutina sería DESTRUIDA cuando esa referencia salga del alcance al final de la subrutina – Dancrumb

+0

No devolvería un resultado de referencia débil en una copia implícita (lo que resultaría en una referencia fuerte) siendo devuelto)? – Cameron

+2

@Dancrumb, @Cameron, puede devolver un objeto sobrecargado que almacena una referencia debilitada. – ysth

12

Cada vez que copie una referencia en una nueva variable, el recuento de referencias se incrementará. Esto es cierto cuando se copia una referencia débil o fuerte.

my $obj = {}; # 1 reference to {} stored in $obj 

my $copy = $obj; # 2 references 

weaken $obj;  # 1 reference 

en este punto, si $copy sale del ámbito, la cuenta de referencia cae a cero, y la memoria serán liberados. Supongamos ahora el siguiente código:

my $newref = $obj; # 2 references 

undef $copy;  # 1 reference 

Si Perl conserva la referencia débil en $newref, entonces el hash se dealocated inesperadamente cuando $copy fue despejada. Esto rompería la expectativa de que cuando copies una referencia, por lo menos se mantendrá mientras dure la copia.

En resumen, si las referencias débiles persistieran en una tarea, le obligaría a ensuciar su código con innumerables controles de debilidad, y requeriría alguna otra manera de desvincular una variable, todo para evitar los inevitables problemas de suicidio variable.

Cuestiones relacionadas