Forum > General

Punteros y Objetos / Pointers and Object

(1/2) > >>

egbaquela:
*********
En español
*********

Hola a todos: los consulto por un problema que estoy teniendo con FreePascal desde ayer y por mas que lo pienso no lo puedo resolver. Mi programa tiene 2 clases, "TPadre" y "THijo". Los hijos, como no se el número a priori, están definidos en un array dinámico:

--- Code: ---type
  pHijo = ^Hijo;
 
  Hijo = class
  ...
  end;

var

  Hijos: array of THijo;


--- End code ---

El objeto "Padre" tiene un campo de tipo puntero que apunta a los hijos que tiene asociado. Este campo es un array dinámico:


--- Code: ---TPadre = class
  ...
  teHijos: array of pHijo
  ...
end;


--- End code ---

(Puede haber varias variables padres, y los hijos pueden estar asignados a mas de un padre, por lo cual no puedo definir el array "Hijos" dentro de TPadre).
Para crear dinámicamente a los hijos, tengo definido el siguiente procedimiento:


--- Code: ---
procedure CrearHijo(iCod: integer; strNombre: string; Padre: TPadre);
begin
  setlength(Hijos, length(Hijos) +1);
  Hijos[high(Hijos)]:= THijo.create(iCod, strNombre) ;
  VincularHijos(Padre, Hijos[high(Hijos)]);
end;


--- End code ---

Donde "VincularHijos" es:

--- Code: ---procedure VincularHijos(var Padre: TPadre; var Hijo: THijo);
var
  i: integer;
begin
  i:=length(Padre.teHijos);
  setlength(Padre.teHijos, i+1);
  Padre.teHijos[i]:= @Hijo;
end;

--- End code ---

En principio funciona bien, no tengo problemas en hacer cosas como:


--- Code: ---  writeln(Padre.teHijos[i]^.strNombre);

--- End code ---

Pero cuando tengo mas de tres hijos creados y asignados al padre, resulta que una instrucción como la anterior me tira error para valores pequeños de "i". Lo raro es que si el array "Hijos" es estático, puedo hacer "Padre.teHijos^.strNombre" para cualquier hijo, no tengo el problema anterior. Es como si setlength, en el procedimiento "CrearHijos" modificara la ubicación en memoria de los elementos del array (pero no siempre, sinó solo algunas veces).
Para que vean un caso puntual, definido "Hijos" en forma dinámica, le cargué 14 variables "Hijo". Desde "Padre.teHijos[0]^." a "Padre.teHijos[7]^" me tira el error "SIGSEGV Error" en tiempo de ejecución, para los "Padre.teHijos[8]^" a "Padre.teHijos[13]^" el código funciona correctamente.
¿Alguién sabe que puede estar pasando?

PD: Uso Lazarus 0.9.28.2 con fpc 2.2.4 .

****************************************************************
****************************************************************

********************
In (very, very bad) english
********************

Hi: I consult you for a problem I'm having with FreePascal since yesterday and as much as I think I can not solve. My program has 2 class, "TPadre" (Father) and "THijo" (Son). The Hijo object, as no a priori number, are defined in a dynamic array:

:

--- Code: ---type
  pHijo = ^Hijo;
 
  Hijo = class
  ...
  end;

var

  Hijos: array of THijo;


--- End code ---

The "Padre" object has a field of type pointer to the "Hijo" that is associated. This field is a dynamic array:


--- Code: ---TPadre = class
  ...
  teHijos: array of pHijo
  ...
end;


--- End code ---

(There may be several variables TPadre,  and THijo can be assigned to more than one father, so I can not define the array "Hijos" in TPadre).
To dynamically create the "Hijo", I have defined the following procedure:

--- Code: ---
procedure CrearHijo(iCod: integer; strNombre: string; Padre: TPadre);
begin
  setlength(Hijos, length(Hijos) +1);
  Hijos[high(Hijos)]:= THijo.create(iCod, strNombre) ;
  VincularHijos(Padre, Hijos[high(Hijos)]);
end;


--- End code ---

"VincularHijos" is:

--- Code: ---procedure VincularHijos(var Padre: TPadre; var Hijo: THijo);
var
  i: integer;
begin
  i:=length(Padre.teHijos);
  setlength(Padre.teHijos, i+1);
  Padre.teHijos[i]:= @Hijo;
end;

--- End code ---

In principle it works well, I have no trouble doing things like:


--- Code: ---  writeln(Padre.teHijos[i]^.strNombre);

--- End code ---

But when I have more than three "THijo" created and assigned to the "Padre",  a statement like the above throw me error for small values of "i". The strange thing is that if the array "Hijos" is static, I can do "Padre.teHijos ^. StrName" for any "THijo", I don´t have the above problem. Is as if SetLength, in the procedure "CrearHijos", modify the memory location of array elements (but not always, but only a few times).
To see a punctual case, I defined as "THijo", 14 variables in the dynamic array "Hijos". From "Padre.teHijos [0] ^" to "Padre.teHijos [7] ^" I throw the error "Error SIGSEGV" at run time, from "Padre.teHijos [8] ^" to "Padre.teHijos [ 13] ^ "the code works correctly.
Does anyone know what could be happening?


PD: I use Lazarus 0.9.28.2 with fpc 2.2.4 .


mas steindorff:
I've had issues with setlength too.  I have gone to either fixed array size or use a TobjectList for the more complex objects

Are you expecting a TPadre to have more than say [100] pHijo?  if not, memory the cost of the extra memory is small and just use a fixed array size for the pointers.


garlar27:
Mmmh!!!

   Me parece extraño el error que tenés, ya que a mí no me pasa. De todos modos yo hubiera buscado una solución diferente a la del array dinámico.

   Tenés que tener en cuenta que por definición de tu problema (Un Padre con muchos Hijos y Un Hijo con Muchos Padres) te conviene crear una única lista de registros de cada una de estas relaciones (NombrePadre, PunteroAPadre, NombreHijo, PunteroAHijo).

   Lo primero que se me ocurre es usar un TMemDataSet con estos datos.
   Por qué? Porque podés usar filtros para limitar las búsquedas.

   Lo segundo es usar este registro en un array dinámico o mejor aún: en un TList, ya que éste te permite ordenarlo y además vos podés definir la manera de hacerlo.


--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---TRelacion = record   NombrePadre: string;   Padre: TPadre;   NombreHijo: string;   Hijo: THijo;end; PRelacion = ^TRelacion; 

=======================

Mmmh!!!

   I think that error is strange, since I don't have it. Anyway ... I would have used a different approach instead of a Dynamic Array.

   According to your problem definition (a Parent can have Many Childs and a Child can have Many Parents) I would used a single list with records of every relationships (ParentName, PointerToParent, ChildName, PointerToChild).

   The first I can think of is a TMemDataSet with the above mentioned fields.
   Why? Because you can use filters to limit the search of a relationship.

   The second one is to use the following record in a dynamic array, or even better: in a TList which allows you to sort the List with a custom comparison function.


--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---TRelationship = record   ParenName: string;   Parent: TParent;   ChildName: string;   Child: TChild;end; PRelationship = ^TRelationship; 

egbaquela:
mas steindorff/garlar27 : thank for your response.

mas steindorff: I don´t really know how many PHijo could have in a TPadre, but 100 is a reasonable number. I will consider to work with a static array, I suppose that I won´t have problem with that size.

garlar27: me gustó mucho tu idea de la lista de relaciones. Voy a implementarla junto al TMemDataSet.

Greeting, Gabriel.

Laksen:
Try something like this. A class is always a reference, so no need for pointers, or passing by reference

--- Code: ---type
  THijo = class
  ...
  end;

var
  Hijos: array of THijo;

--- End code ---


--- Code: ---TPadre = class
  ...
  teHijos: array of THijo
  ...
end;

--- End code ---


--- Code: ---procedure CrearHijo(iCod: integer; strNombre: string; Padre: TPadre);
begin
  setlength(Hijos, length(Hijos) +1);
  Hijos[high(Hijos)]:= THijo.create(iCod, strNombre) ;
  VincularHijos(Padre, Hijos[high(Hijos)]);
end;

procedure VincularHijos(Padre: TPadre; Hijo: THijo);
var
  i: integer;
begin
  i:=length(Padre.teHijos);
  setlength(Padre.teHijos, i+1);
  Padre.teHijos[i]:= Hijo;
end;

--- End code ---


--- Code: ---  writeln(Padre.teHijos[i].strNombre);

--- End code ---

Navigation

[0] Message Index

[#] Next page

Go to full version