Fonction retournant un objet

Résolu
Sat83 Messages postés 166 Date d'inscription mardi 11 novembre 2003 Statut Membre Dernière intervention 13 octobre 2008 - 27 juil. 2007 à 17:41
Sat83 Messages postés 166 Date d'inscription mardi 11 novembre 2003 Statut Membre Dernière intervention 13 octobre 2008 - 11 août 2007 à 22:14
Bonjour a tous!

J'ai un probleme avec une fonction retournant un objet. D'habitude pour les fonctions retournant un objet, je n'ai pas de soucis. Voilà un exemple bateau qui fonctionne :

function TForm1.getList: TstringList;

var list : TstringList ;

begin

 list := TstringList.Create ;  // CREATION

 list.Add('1') ;

 list.Add('2') ;

 Result : = list ;

end;

procedure TForm1.Button1Click(Sender: TObject);
var TmpList : TstringList ;
begin
 tmpList := getList ;
 ListBox1.Items.Assign( tmpList );
 TmpList.Destroy ;    // DESTRUCTION
end;

Avec un TStringList, aucun soucis et aucune fuite de mémoire, tout les objet créee sont détruit.

Le problème vient maintenant avec l'exemple çi-dessous :

function TForm1.getDataSource: TDatasource;
var aSource : TDatasource ;
begin
 aSource : = TDatasource.Create(nil) ;
 [...]
 Result := aSource ;
end;

procedure TForm1.Button2Click(Sender: TObject);
var tmpSource : TDatasource ;
begin
 tmpSource := getDataSource ;
 DBGrid1.DataSource.Assign( tmpSource );  // ERREUR !
 tmpSource.Destroy ;
end;

C'est pourtant l'equivalant du TStringList avec un TDataSource, mais ca ne fonctionne pas! L'erreur vient de la methode Assign du TDataSource. Bien sur une solution serait :

procedure TForm1.Button2Click(Sender: TObject);

var tmpSource : TDatasource ;

begin

 tmpSource : = getDataSource ;

 DBGrid1.DataSource := tmpSource ;  //on affecte directement

end;

Mais bonjour les fuites de mémoires!
La methode getDataSource est appelé à plein d'endroit.

Si quelqu'un a une idée pour resoudre mon probleme, je suis preneur! En esperant que j'ai reussi à l'exposé à peut pret correctement!

Merci d'avance...

10 réponses

Sat83 Messages postés 166 Date d'inscription mardi 11 novembre 2003 Statut Membre Dernière intervention 13 octobre 2008
11 août 2007 à 22:14
Bonsoir a tous!

Je viens proposer la solution que j'ai finnallement adoptée. Après pas mal de recherche et mon ami FastMM4 qui m'indiquait les eventuelles fuites de mémoire, j'ai trouvé la solution qui resout mon problème.

Le problème de départ était de savoir comment bien détruire les objet créer dans une fonction. J'ai abandonné la piste de la redefinition du Assign qui aurair pu resoudre ce probleme en copiant un objet dans un autre.

Au final voilà comment je m'y prend :

var MyObjectArray : Array of TMyObject ;

function TBlabla.getObject : TMyObject;
var index : integer;
    obj: TMyObject;
begin
  obj:= TMyObject.Create ;
  index := length( MyObjectArray ) ;

  SetLength(MyObjectArray , index  + 1) ;
  MyObjectArray[index] := obj ;
  Result := obj ;
end;

procedure TBlabla.DestroyObject;
var index : integer ;
     l : integer ;
begin
l := length( MyObjectArray )  ;
 if l = 0 then Exit ;
  for index := 0 to l do
  begin
   if Assigned( MyObjectArray[index] ) then
      MyObjectArray[index].Free ;
   end;
end;

Donc en faite je sauvegarde tout mes objet créer dans un tableau, et je me charge de les détruire à la fin de mon programme. C'est pas tout a fait ce que je souhaitais faire au depart, mais ça permet de bien detruire les objet crée dans une fonction.

Si jamais ça peut permetre d'aidé quelqu'un qui est confronté au même probleme!

Merci en tout cas a ceux qui auront tenté de m'aidé!
3
WhiteHippo Messages postés 1154 Date d'inscription samedi 14 août 2004 Statut Membre Dernière intervention 5 avril 2012 3
27 juil. 2007 à 20:18
Bonsoir

Un petit rappel :

  DBGrid1.DataSource := tmpSource ;

n'est pas identique à

  DBGrid1.DataSource.Assign( tmpSource ); 


Dans le premier cas, l'opérateur d'affectation := fait que DataSource désignera le même objet que tmpSource, tandis que dans le second cas la méthode Assign ne fait que recopier le contenu référencé par tmpSource dans un autre objet, ici DataSource, donc celui ci doit être déjà créé.

P.S. Crée un DBGrid auquel tu affectes un DataSource, puis un second DataSource. Et essayes le code suivant
  DBGrid1.DataSource.Assign( DataSource1 );

Cordialement.
<hr />"L'imagination est plus importante que le savoir." Albert Einstein
0
florenth Messages postés 1023 Date d'inscription dimanche 1 août 2004 Statut Membre Dernière intervention 17 août 2008 3
27 juil. 2007 à 21:05
Salut !

Petit rappel sur le rappel :

Image1.Picture := NewPicture; // (Image1: TImage - NewPicture: TPicture)

Ceci n'affecte pas mais assigne ! Tu auras donc une copie de l'image.
Pourquoi ? Car le setter de la propriété Picture est écrit comme cela:

procedure TImage.SetPicture(Value: TPicture);
begin
  FPicture.Assign(Value);
end;

Pour le DataSet, je ne sais pas. Mais à mon avis c'est bien une affectation comme l'affirme WhiteHippo
0
Sat83 Messages postés 166 Date d'inscription mardi 11 novembre 2003 Statut Membre Dernière intervention 13 octobre 2008
28 juil. 2007 à 01:01
Bonsoir!

Merci pour vos reponse...

En faite je connais la distinction entre l'affectation et l'assignation. Mais je crois que j'ai du mal m'exprimer dans mon premier post.

La methode Assign pas defaut dans le TPersistant ne fais qu'un appel a la methode AssignTo:

procedure TPersistent.Assign(Source: TPersistent);
begin
  if Source <> nil then Source.AssignTo(Self) else AssignError(nil);
end;

Le probleme est que le TDataSource n'implemente pas la methode AssignTo, d'où l'exception généré. En gros dans l'exemple avec un TStringList il n'y a pas de soucis car la methode Assign est surchargé, mais le TDataSource ne surcharge ni Assign ni AssignTo

Donc la question était plutot de savoir comment faire pour creer une fonction qui retourne un TDataSource sans fuite de mémoire (et sans implementé à la main un AssignTo au TDataSource). Ou plus globalement comment copier un objet dans un autre sans passé par Assign.

En esperant que j'ai pu etre un peu plus clair (mais il est tard donc c'est pas gagné ) Merci d'avance
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
f0xi Messages postés 4205 Date d'inscription samedi 16 octobre 2004 Statut Modérateur Dernière intervention 12 mars 2022 35
28 juil. 2007 à 01:14
function TForm1.GetList : TStrings;
begin
  result := TstringList.Create;
  with Result do
  begin
    BeginUpdate;
    try
      Add('1');
      Add('2');
    finally
      EndUpdate;
    end;
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
var TmpList : TStrings;
begin
  TmpList := GetList;
  ListBox1.Items.Assign( TmpList );
  TmpList.Free;
end;




et
si on regarde la structure de TDataSource, aucune methode Assign ou
AssignTo n'est surchargée ... en gros, seul les données de l'ancetre
(TComponent) sont copiées dans la source ...

alors que pour TStrings (Ancetre de TStringList) on y trouve :

procedure TStrings.Assign(Source: TPersistent);
begin
  if Source is TStrings then
  begin
    BeginUpdate;
    try
      Clear;
      FDefined := TStrings(Source).FDefined;
      FNameValueSeparator := TStrings(Source).FNameValueSeparator;
      FQuoteChar := TStrings(Source).FQuoteChar;
      FDelimiter := TStrings(Source).FDelimiter;
      AddStrings(TStrings(Source));
    finally
      EndUpdate;
    end;
    Exit;
  end;
  inherited Assign(Source); // Vers TPersistent.Assign
end;

voila.
0
f0xi Messages postés 4205 Date d'inscription samedi 16 octobre 2004 Statut Modérateur Dernière intervention 12 mars 2022 35
28 juil. 2007 à 01:16
ah j'avais pas vus ta reponse...

Donc la question était plutot de savoir comment faire pour creer une
fonction qui retourne un TDataSource sans fuite de mémoire (et sans
implementé à la main un AssignTo au TDataSource). Ou plus globalement
comment copier un objet dans un autre sans passé par Assign.

tu peu faire :

procedure TForm1.GetDataSource(DataSource : TDataSource);
begin
  if not Assigned(DataSource) then
     exit;
 
  { remplissage de DataSource }
end;
0
f0xi Messages postés 4205 Date d'inscription samedi 16 octobre 2004 Statut Modérateur Dernière intervention 12 mars 2022 35
28 juil. 2007 à 01:21
sinon pour deriver TDataSource c'est assé simple :

uses .... , DB;

type
  TDataSource = class(DB.TDataSource)
  public
    procedure Assign(Source : TComponent); override;
  end;

  TForm1 = class(TForm)
  ...
  end;

implementation

procedure TDataSource.Assign(Source : TComponent);
begin
  if Source is TDataSource then
  begin
    with Source do
    begin
      Self.{property} := {source property}
    end;
  end else
    inherited Assign(Source);
end;
   
0
cs_Delphiprog Messages postés 4297 Date d'inscription samedi 19 janvier 2002 Statut Membre Dernière intervention 9 janvier 2013 32
5 août 2007 à 23:21
Petit rappel à l'ordre !
@ Sat83 : valides-tu les réponses oui ou non ?
Par politesse, il serait bon de donner signe de vie à ceux qui se sont décarcassés pour toi.


May Delphi be with you !


<hr color="#008000" />
Pensez à cliquer sur Réponse acceptée lorsque la réponse vous convient.
http://www.afipa.net/
0
Sat83 Messages postés 166 Date d'inscription mardi 11 novembre 2003 Statut Membre Dernière intervention 13 octobre 2008
6 août 2007 à 11:56
Bonjour bonjour!

Ce n'est pas du tout par impolitesse que je n'ai pas repondu aux messages laissés sur ce post!

Et bien evidemment je remercie ceux qui ont pris la peine de lire mon message et proposé une solution à mon problème.

Pour le moment je n'ai pas eu le temps de continué mon projet, donc en
attendant je laisse ce post ouvert à d'autres idées éventuelles. Sinon,
je pense que j'adopterais la solution de Foxi ( a savoir dériver la
methode Assign ) meme si je préfererais l'éviter.

Je n'ai pas cliqué sur "reponse accepté" au cas où une autre solution serait proposée pour copier un objet dans un autre.

Merci en tout cas
0
Sat83 Messages postés 166 Date d'inscription mardi 11 novembre 2003 Statut Membre Dernière intervention 13 octobre 2008
10 août 2007 à 11:21
Re-bonjour a tous !

Alors aujourd'hui je me suis motivé pour me relancé dans mon mini projet et donc tenté de résoudre mon probleme de copie d'objet dans un autre.

J'ai donc tenté d'utilisé les deux solutions proposé par Foxi, mais le problème malheureusement persiste!

J'ai donc dérivé la classe TDataSource pour pouvoir implémenté la methode Assign, jusque là pas de problème. Le problème c'est qu'il y a des objets dans les propriété du TDataSource (TDataSet en locurance) qui ne possède pas de methode Assign !

Donc en gros, en utilisant une simple affectation pour TDataSet dans le Assign de TDataSouce, les deux objets auront leurs propriété DataSet pointant sur les même objet ! Alors que ce que je souhaiterais c'est avoir deux objet completement indepandant.

Je sais, ca devient compliqué, moi même je m'y perd dans mes explications !

Je ne sais pas si il a vraiment une solution a ce que je veut faire!

Mais si jamais vous en avez d'autres a proposé, n'hesité pas!

Merci
0
Rejoignez-nous