Fonction retournant un objet [Résolu]

Sat83 172 Messages postés mardi 11 novembre 2003Date d'inscription 13 octobre 2008 Dernière intervention - 27 juil. 2007 à 17:41 - Dernière réponse : Sat83 172 Messages postés mardi 11 novembre 2003Date d'inscription 13 octobre 2008 Dernière intervention
- 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...
Afficher la suite 

Votre réponse

10 réponses

Meilleure réponse
Sat83 172 Messages postés mardi 11 novembre 2003Date d'inscription 13 octobre 2008 Dernière intervention - 11 août 2007 à 22:14
3
Merci
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é!

Merci Sat83 3

Avec quelques mots c'est encore mieux Ajouter un commentaire

Codes Sources a aidé 120 internautes ce mois-ci

Commenter la réponse de Sat83
WhiteHippo 1270 Messages postés samedi 14 août 2004Date d'inscription 5 avril 2012 Dernière intervention - 27 juil. 2007 à 20:18
0
Merci
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
Commenter la réponse de WhiteHippo
florenth 1105 Messages postés dimanche 1 août 2004Date d'inscription 17 août 2008 Dernière intervention - 27 juil. 2007 à 21:05
0
Merci
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
Commenter la réponse de florenth
Sat83 172 Messages postés mardi 11 novembre 2003Date d'inscription 13 octobre 2008 Dernière intervention - 28 juil. 2007 à 01:01
0
Merci
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
Commenter la réponse de Sat83
f0xi 4304 Messages postés samedi 16 octobre 2004Date d'inscription 9 mars 2018 Dernière intervention - 28 juil. 2007 à 01:14
0
Merci
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.
Commenter la réponse de f0xi
f0xi 4304 Messages postés samedi 16 octobre 2004Date d'inscription 9 mars 2018 Dernière intervention - 28 juil. 2007 à 01:16
0
Merci
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;
Commenter la réponse de f0xi
f0xi 4304 Messages postés samedi 16 octobre 2004Date d'inscription 9 mars 2018 Dernière intervention - 28 juil. 2007 à 01:21
0
Merci
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;
   
Commenter la réponse de f0xi
cs_Delphiprog 4580 Messages postés samedi 19 janvier 2002Date d'inscription 9 janvier 2013 Dernière intervention - 5 août 2007 à 23:21
0
Merci
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/
Commenter la réponse de cs_Delphiprog
Sat83 172 Messages postés mardi 11 novembre 2003Date d'inscription 13 octobre 2008 Dernière intervention - 6 août 2007 à 11:56
0
Merci
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
Commenter la réponse de Sat83
Sat83 172 Messages postés mardi 11 novembre 2003Date d'inscription 13 octobre 2008 Dernière intervention - 10 août 2007 à 11:21
0
Merci
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
Commenter la réponse de Sat83

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.