Confusión de propiedad de Delphi
memory-management components (2)
¿Por qué está pasando esto?
Tiene sentido y es por diseño. ¿Qué crees que debería pasarle a los controles huérfanos cuando se destruye el padre? ¿Deberían comenzar a flotar repentinamente como ventanas de nivel superior? Probablemente no. ¿Deberían volver a criar a otro control? ¿Cúal?
who is destroying the object if I pass in an owner?
Parent
, si se asigna y se libera primero. TWinControl
anula el TComponent
de TComponent
para liberar primero sus controles secundarios (el destructor heredado solo se llama más adelante). Los controles secundarios notify su Owner
sobre la destrucción, lo que los elimina de su lista de componentes de propiedad. Es por eso que el Propietario no intenta liberar su objeto nuevamente más tarde en su destructor.
Si Parent
es el mismo objeto que Owner
, también se aplica lo anterior.
Si Parent
y Owner
son dos objetos diferentes, y libera al Propietario primero, entonces el componente Owner libera todos sus componentes TComponent
(vea el TComponent
de TComponent
). Su objeto es un descendiente TControl
y TControl
anula el destructor para llamar a SetParent(nil);
que elimina la instancia de la lista de controles secundarios de los padres. Es por eso que el padre no intenta liberar su objeto nuevamente más tarde en su destructor.
Siempre pensé que el propietario es responsable de destruir los controles visuales y que puedo controlar la destrucción manualmente si pierdo el control como propietario.
Considere el siguiente ejemplo:
TMyForm = class (TForm)
private
FButton : TButton;
end;
...
FButton := TButton.Create(nil); // no owner!!
FButton.Parent := Self;
Esperaría que este botón produjera una pérdida de memoria pero no lo hace y, de hecho, se llama al destructor de TButton
.
La investigación adicional mostró que el destructor TWinControl
contiene el siguiente fragmento de código:
I := ControlCount;
while I <> 0 do
begin
Instance := Controls[I - 1];
Remove(Instance);
Instance.Destroy;
I := ControlCount;
end;
que parece que está destruyendo los componentes secundarios (los que tienen el elemento principal configurado para el control).
No esperaba que el control padre destruyera el control. ¿Alguien puede explicar por qué está sucediendo esto? ¿Y quién está destruyendo el objeto si paso a un propietario?
La primera versión a la que tengo acceso ahora es Delphi 5 y el destructor TWinControl
tiene el código que publicaste allí, por lo que este comportamiento ha estado en funcionamiento durante mucho tiempo. Y cuando lo piensas, tiene sentido, los Controls
son componentes visuales y cuando destruyes su contenedor (Padre), entonces tiene sentido destruir al niño también. El destructor de TWinComponent no puede decidir qué hacer con ellos (¿ocultarlos?). Enviarlos a Parent.Parent. ¿Pero qué pasa si el Parent actual es una ventana de nivel superior, es decir, no tiene Parent? Etc.). Entonces, los diseñadores de la VCL decidieron que esta es la opción más segura, evitando las fugas de memoria / manejo (especialmente las manijas de las victorias, donde en los primeros días era premium, por lo que evitar las fugas era probablemente la principal prioridad). Por lo tanto, si desea que los niños se queden, debe volver a criarlos antes de destruir el contenedor.
Por cierto. si pasa un Propietario, entonces TComponent.DestroyComponents;
(llamado por TComponent.Destroy
) destruye el componente.