IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langage Delphi Discussion :

Tableau Dynamique pointant sur Tableau Statiques


Sujet :

Langage Delphi

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Expert éminent
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    14 090
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 14 090
    Par défaut Tableau Dynamique pointant sur Tableau Statiques
    Pour le plaisir de ne pas utiliser Copy dans un code que j'ai fait ce matin (je fais une DLL pour un partenaire, où j'utilise volontairement le moins de lib que possible, donc je réinvente de deux-trois trucs que j'ai déjà écrit comme une persistance objet mais en version ultra ligth), j'ai bidouillé un truc, et j'aimerais savoir ce que vous en pensez et aussi éclairer ma lanterne ...

    j'ai plusieurs tableau constants qui ont cette forme, ils ont juste des tailles différentes ...

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    const
      PROPERTIES_MAPPING_xxx: array[0..17] of TPropertyMapping =
        (
          (PropertyName: 'p1'; FieldName: 'f1';        ),
          (PropertyName: 'p2'; FieldName: 'f2';     ),
       ...
       );
    j'ai un objet ancêtre à mes objets, qui mappent des propriétés publiés et des champs dans une table, j'ai donc

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
      TSearchObject = class(TPersistent)
      private
        FPropertiesMapping: array of TPropertyMapping;
      protected
        procedure LoadFromDataSet(ADataSet: TDataSet);
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    procedure TSearchObject.LoadFromDataSet(ADataSet: TDataSet);
    var
      I: Integer;
      Field: TField;
      PropertyValue: Variant;
    begin
      for I := Low(FPropertiesMapping) to High(FPropertiesMapping) do
      begin
        Field := ADataSet.FindField(FPropertiesMapping[I].FieldName);
        if Assigned(Field) then
        begin
          if Field.IsNull then
          begin
            PropertyValue := Null;
          end
          else
          begin
            if Field.DataType = ftDate then
              PropertyValue := Field.AsDateTime
            else
              PropertyValue := Field.AsString;
          end;
          TEpcRTTIWrapper.SetPropertyValue(Self, FPropertiesMapping[I].PropertyName, PropertyValue);
        end
        else
          raise ENeoScopeLADAPIError.Create(ERR_SEARCH_INVALID_DB_MAPPING);
      end;
    end;
    Vous noterez donc que l'ancêtre utilise FPropertiesMapping, le tableau dynamique, donc voilà, c'est juste que ce tableau n'est initialisé uniquement (et obligatoirement) par les descendants de TSearchObject ... dans une surcharge du constructeur ...

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    constructor THeritedObject.Create(APointer: Pointer);
    begin
      ....
     
      Pointer(FPropertiesMapping) := @PROPERTIES_MAPPING_HERITED;
      PInteger(Integer(FPropertiesMapping) - 4)^ := Length(PROPERTIES_MAPPING_HERITED);
    end;
    dans l'ancêtre, évidemment, je nettoye mon tableau dynamique bidonné, sinon gare au dégat

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    destructor TSearchObject.Destroy();
    begin
      PInteger(Integer(FPropertiesMapping) - 4)^ := 0;
      FPropertiesMapping := nil;
     
      ...
    end;
    Alors voici enfin ma question, si je mets que l'affectation à nil (sans la modif de la longueur), et bien, pas de violation d'accès dans l'immédiat mais un comportement assez ératique de mon programme par la suite (le Connect de mon TMyConnection fait une violation d'accès, c'est tombé sur lui va savoir pourquoi ...)

    Si je met que l'affectation de la longueur (sans le nil), ben cela semble fonctionner,

    si je mets les deux, cela semble aussi fonctionner, et ça me rassure même si je ne sais pas si cela fait grand chose ...

    Alors est-ce que l'affectation à nil est utile ou pas ? ou pire était dangereuse puisque cela appele DynArrayClear ?

    EDIT : autre question sur une éventulle fuite mémoire, en théorie FPropertiesMapping celui créé par l'instanciation de l'objet n'est qu'une coquille vide ? il n'a pas d'élément donc ne pointe sur aucune zone mémoire, la seule mémoire consommée est le compteur de référence et la longueur du tableau, et le pointeur lui même bien sur ... donc normalement c'est libéré ! non ?
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  2. #2
    Expert confirmé

    Avatar de sjrd
    Homme Profil pro
    Directeur de projet
    Inscrit en
    Juin 2004
    Messages
    4 517
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : Suisse

    Informations professionnelles :
    Activité : Directeur de projet
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2004
    Messages : 4 517
    Par défaut
    Aaaaaaarrrrrgggggghhhh !!!!
    Désolé mais là, c'est vraiment affreux

    En plus, il n'y a aucun moyen de faire ça sans risque. A cause du compteur de références.

    Déjà, quand tu fais :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    constructor THeritedObject.Create(APointer: Pointer);
    begin
      ....
     
      Pointer(FPropertiesMapping) := @PROPERTIES_MAPPING_HERITED;
      PInteger(Integer(FPropertiesMapping) - 4)^ := Length(PROPERTIES_MAPPING_HERITED);
    end;
    Où sont censés être les 4 octets pour la longueur ? Ils sont avant le tableau, certes, mais cet endroit n'est pas réservé ! D'ailleurs, les 4 octets encore en-dessous, pour le comptage de références, ne sont pas réservés non plus.

    Et même s'ils étaient réservés, ils se trouvent dans les sections "constantes", donc c'est casse-gueule : suffit qu'elles soient interdites en écriture et c'est l'AV.

    La longueur, encore, tu pourrais la déclarer et renseigner constante. Ca fonctionnerait. Mais le compteur de références, il est obligé de changer durant l'exécution, donc il n'a pas le droit d'être dans une section constante.

    Et comme les tableaux dynamiques n'ont pas de sentille pour les compteurs de références ne devant pas être modifiés, tu n'y arriveras pas. (les string, elles, ont cette sentinelle : si le RefCounter = -1, alors il n'est jamais modifié, et la chaîne n'est jamais libérée - c'est utilisé par les chaînes constantes, justement ).

    Conclusion, euh : retourne à la bonne vieille recopie de ton tableau Ca peut être fait dans le constructeur de l'ancêtre avec un paramètre de type tableau ouvert.
    sjrd, ancien rédacteur/modérateur Delphi.
    Auteur de Scala.js, le compilateur de Scala vers JavaScript, et directeur technique du Scala Center à l'EPFL.
    Découvrez Mes tutoriels.

  3. #3
    Expert éminent
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    14 090
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 14 090
    Par défaut
    Donc, en fait, le fait que cela fonctionne c'est juste de la chance, tu peux qu'en fait, au moment, où j'utilise le tableau, la structure interne du tableau (appelons là TArrayRec à la façon de TStrRec de SysUtils) n'est pas alloué, et donc en fait, j'écrit n'importe où dans mon objet ... je te fais confiance vu tes fonctions sur la sérialisation de tableau ...

    bon donc un Copy avec paramètres
    J'avais commencé par un Copy, mais comme il m'a envoyé baladé, je me suis tient, faisons un essai ...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
      FPropertiesMapping := Copy(PROPERTIES_MAPPING_xxx, Low(PROPERTIES_MAPPING_xxx), High(PROPERTIES_MAPPING_xxx));
    Cela ne veut pas, c'est con, non, faut que je passe par un SetLength puis CopyMemory ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
      SetLength(FPropertiesMapping, Length(PROPERTIES_MAPPING_xxx));
      CopyMemory(@FPropertiesMapping[0], @PROPERTIES_MAPPING_xxx[0], SizeOf(PROPERTIES_MAPPING_xxx));
    Cela ne copie finalement que les pointeurs, ce n'est pas si couteux que cela ... c'est moins fun !

    le SUB EAX, 8 dans _DynArrayClear, semble confirmer que j'écrit ailleurs que dans le tableau ...

    EDIT

    Citation Envoyé par sjrd Voir le message
    Et même s'ils étaient réservés, ils se trouvent dans les sections "constantes", donc c'est casse-gueule : suffit qu'elles soient interdites en écriture et c'est l'AV..
    lol, je ne l'avais pas vu celle là (le fait que j'écrit en fait -4 devant ma constance), si j'avais fait, mais est-ce vraiement constant ? c'est une constante typée donc en fait en Delphi, ça ne donne pas une variable, que l'on peut modifier ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
      PInteger(Integer(FPropertiesMapping) - 4)^ := Length(PROPERTIES_MAPPING_PATIENT);
      Pointer(FPropertiesMapping) := @PROPERTIES_MAPPING_PATIENT;
    la j'ai clairement une erreur, j'aurais compris que le tableau contenait bien nil et donc pas de mémoire pour -4 et -8 ...

    Citation Envoyé par sjrd Voir le message
    Conclusion, euh : retourne à la bonne vieille recopie de ton tableau Ca peut être fait dans le constructeur de l'ancêtre avec un paramètre de type tableau ouvert.
    Effectivement, je pourrais redéfinir un autre constructeur, mais j'ai pas envie, donc je le code spécifiquement dans les constructeurs des hérités (j'en ai pas beaucoup)

    EDIT 2 : J'ai testé le coup de la variable juste avant

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    const
      PROPERTIES_MAPPING_xxx_REFCOUNT: Cardinal = 0;
      PROPERTIES_MAPPING_xxx_LENGTH: Cardinal = 0;
      PROPERTIES_MAPPING_xxx: array[0..7] of TPropertyMapping =
    Yep, ça écrit bien dedans, lol, vu mon code, le compteur de Ref, ne peut pas bouger, j'utilise le membre privée sans le passer en paramètre, normalement ça ne bouge pas, d'ailleurs, j'ai eu beau faire des essais, je n'ai jamais réussi à voir un RefCount monté dans une string, si tu as un code pour que je puisse visualiser le phénomène cela m'interesse ...
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  4. #4
    Expert confirmé

    Avatar de sjrd
    Homme Profil pro
    Directeur de projet
    Inscrit en
    Juin 2004
    Messages
    4 517
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : Suisse

    Informations professionnelles :
    Activité : Directeur de projet
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2004
    Messages : 4 517
    Par défaut
    Citation Envoyé par ShaiLeTroll Voir le message
    Donc, en fait, le fait que cela fonctionne c'est juste de la chance, tu peux qu'en fait, au moment, où j'utilise le tableau, la structure interne du tableau (appelons là TArrayRec à la façon de TStrRec de SysUtils) n'est pas alloué, et donc en fait, j'écrit n'importe où dans mon objet ...
    Voilà c'est ça. En fait, plus exactement, tu écris n'importe où dans la mémoire
    Citation Envoyé par ShaiLeTroll Voir le message
    bon donc un Copy avec paramètres
    J'avais commencé par un Copy, mais comme il m'a envoyé baladé, je me suis tient, faisons un essai ...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
      FPropertiesMapping := Copy(PROPERTIES_MAPPING_xxx, Low(PROPERTIES_MAPPING_xxx), High(PROPERTIES_MAPPING_xxx));
    Cela ne veut pas, c'est con, non, faut que je passe par un SetLength puis CopyMemory ?
    Oui je crois que tu es obligé d'utiliser le SetLength + CopyMemory. Copy ne fonctionne qu'avec les tableaux dynamiques.
    Citation Envoyé par ShaiLeTroll Voir le message
    lol, je ne l'avais pas vu celle là (le fait que j'écrit en fait -4 devant ma constance), si j'avais fait, mais est-ce vraiement constant ? c'est une constante typée donc en fait en Delphi, ça ne donne pas une variable, que l'on peut modifier ?
    Sauf option de compilation, je crois que les constantes globales ne peuvent pas être modifiées. Mais quand elles sont typées elles ont effectivement un emplacement en mémoire, contrairement aux constantes non typées qui sont placées comme valeur immédiates.
    Citation Envoyé par ShaiLeTroll Voir le message
    Effectivement, je pourrais redéfinir un autre constructeur, mais j'ai pas envie, donc je le code spécifiquement dans les constructeurs des hérités (j'en ai pas beaucoup)
    Pourtant c'est nettement plus simple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    constructor TAncetre.Create(const PropMappings: array of TPropertiesMapping);
    var
      I: Integer;
    begin
      SetLength(FPropertiesMappings, Length(PropMappings));
      for I := 0 to High(PropMappings) do
        FPropertiesMappings[i] := PropMappings[i];
    end;
     
    constructor THeritedObject.Create(APointer: Pointer);
    begin
      inherited Create(PROPERTIES_MAPPING_HERITED);
      ....
    end;
    Fais quand même gaffe au CopyMemory ! Tes TPropertiesMapping contiennent des données dynamiques (chaînes de caractères). C'est nettement plus sûr de faire une copie membre à membre des record.
    Citation Envoyé par ShaiLeTroll Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    const
      PROPERTIES_MAPPING_xxx_REFCOUNT: Cardinal = 0;
      PROPERTIES_MAPPING_xxx_LENGTH: Cardinal = 0;
      PROPERTIES_MAPPING_xxx: array[0..7] of TPropertyMapping =
    Tu aurais au moins pu les mettre dans un record : ça t'aurait assuré que les emplacements mémoire restent là où ils doivent être.
    Citation Envoyé par ShaiLeTroll Voir le message
    Yep, ça écrit bien dedans, lol, vu mon code, le compteur de Ref, ne peut pas bouger, j'utilise le membre privée sans le passer en paramètre, normalement ça ne bouge pas, d'ailleurs, j'ai eu beau faire des essais, je n'ai jamais réussi à voir un RefCount monté dans une string, si tu as un code pour que je puisse visualiser le phénomène cela m'interesse ...
    Rien de plus simple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    var
      Str, Str2: string;
    begin
      // Pointer(Str) = Pointer(Str2) = nil
      Str := 'Some string';
      UniqueString(Str);
      // Pointer(Str) = @'S' - pardon pour l'abus de langage ^^
      // RefCount(Str) = 1
      Str2 := Str;
      // Pointer(Str) = Pointer(Str2) = @'S'
      // RefCount(Str) = RefCount(Str2) = 2
      WriteLn('RefCount: ', PInteger(Integer(Pointer(Str)) - 8)^;
      Str2 := 'Other string';
      UniqueString(Str2);
      // Pointer(Str2) = 'O'
      // RefCount(Str) = 1 ; RefCount(Str2) = 1
      Str := 'Yet another string';
      // RefCount('Some string') = 0 -> elle est libérée
    end;
    sjrd, ancien rédacteur/modérateur Delphi.
    Auteur de Scala.js, le compilateur de Scala vers JavaScript, et directeur technique du Scala Center à l'EPFL.
    Découvrez Mes tutoriels.

  5. #5
    Expert éminent
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    14 090
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 14 090
    Par défaut
    Merci pour le code,
    si local = -1
    si global = inc
    si membre = inc
    très intéressant, cela explique pourquoi, je ne l'avais jamais vu, n'ayant eu besoin de comprendre ce fonctionnement que sur des chaines locales (un comble ! non ?)
    Le coup du pointeur sur chaine dans un Data d'un TreeView par exemple, je comprends maintenant pourquoi chez certains cela fonctionnait et pas chez moi, c'est l'emplacement de la variable ..., bon étant tout de même courageux, je passé soit par un PString, PChar, un record plus complet ou un objet ...

    Pour le CopyMemory, vu ce que j'avais pondu comme truc, c'est déjà moins pire , et comme c'est constant, cela me va très bien qu'il ne recopie QUE les pointeurs sur les chaines, et n'ont pas toutes les chaines, ... car le CountRef d'une constante reste à -1 donc à chaque fois, il copie la chaine, et même si pour ce projet ce n'est pas grave, je pense à un vieux projets auxquels j'ai participé, et plus j'y pense, et plus je me dit que l'on consommait une quantité mémoire inutile à cause des duplications de chaines à tout va ...

    Pour le constructeur, en fait, j'adore, j'ai le constructeur Virtual; abstract; en public qui est surchargé, et le constructeur avec tableau en protected pour être utiliser dans les surcharges, Excellent en fait ! Merci !
    Et le passage de paramètre fixe\ouvert c'est effectivement sympa !
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  6. #6
    Expert éminent
    Avatar de Paul TOTH
    Homme Profil pro
    Freelance
    Inscrit en
    Novembre 2002
    Messages
    8 964
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 56
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Freelance
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2002
    Messages : 8 964
    Par défaut
    hello,

    j'ai pas tout lu, mais si j'ai bien compris ton problème, le plus simple dans ce cas est de passer par un pointeur

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    type
     PPropertyMapping=^TPropertyMapping;
     
    constructor THeritedObject.Create(APointer: Pointer);
    begin
      ....
     
      FProperties { : PPropertyMapping  } := @PROPERTIES_MAPPING_HERITED[0];
      FPropertyCount := Length(PROPERTIES_MAPPING_HERITED);
    end;
    c'est suffisant si tu ne veux pas accéder aux propriétés par index
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
     
    procedure TSearchObject.LoadFromDataSet(ADataSet: TDataSet);
    var
      I: Integer;
      Field: TField;
      PropertyValue: Variant;
      Prop: PPropertyMapping;
    begin
      Prop:=FProperties;
      for I := 0 to FPropertyCount-1 do
      begin
        Field := ADataSet.FindField(Prop.FieldName);
        if Assigned(Field) then
        begin
          if Field.IsNull then
          begin
            PropertyValue := Null;
          end
          else
          begin
            if Field.DataType = ftDate then
              PropertyValue := Field.AsDateTime
            else
              PropertyValue := Field.AsString;
          end;
          TEpcRTTIWrapper.SetPropertyValue(Self, Prop.PropertyName, PropertyValue);
        end
        else
          raise ENeoScopeLADAPIError.Create(ERR_SEARCH_INVALID_DB_MAPPING);
       inc(Prop); // propriété suivante
      end;
    end;
    Developpez.com: Mes articles, forum FlashPascal
    Entreprise: Execute SARL
    Le Store Excute Store

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Manipulation de pointeur sur tableau dynamique
    Par vincenet dans le forum Débuter
    Réponses: 12
    Dernier message: 09/12/2014, 17h53
  2. [XL-2010] Filtrer tableau dynamique (virtuel) sur VBA
    Par juju152 dans le forum Macros et VBA Excel
    Réponses: 12
    Dernier message: 11/04/2014, 15h33
  3. alternance couleur sur tableau dynamique
    Par asus02 dans le forum Langage
    Réponses: 25
    Dernier message: 13/11/2011, 01h49
  4. [Free Pascal] Redimensionner un tableau dynamique en un tableau statique
    Par tekthoninks dans le forum Free Pascal
    Réponses: 5
    Dernier message: 22/03/2009, 22h38
  5. besoin d'aide sur tableau dynamique
    Par littlesquall dans le forum C
    Réponses: 16
    Dernier message: 02/11/2005, 02h50

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo