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

Contribuez C++ Discussion :

De la rapidité du code [Trucs & Astuces]


Sujet :

Contribuez C++

  1. #161
    Membre actif
    Profil pro
    Ingenieur
    Inscrit en
    Décembre 2003
    Messages
    138
    Détails du profil
    Informations personnelles :
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingenieur

    Informations forums :
    Inscription : Décembre 2003
    Messages : 138
    Points : 280
    Points
    280
    Par défaut
    Bonjour,

    A propos des performances j ai une question qui me chagrine. Voici un exemple simple:
    si dans une methode appelee frequemment j ai par exemple:
    • n traitements independants

    • chaque traitement sera effectue en fonction de son activation et celle ci est connue au depart

    • Chaque traitement prend les meme donnees en entree


    Vaut - il mieux un code comme le suivant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    void method(...)
    {
      if(traitement_1_actif)
      {
        traitement_1(...);
      }
      .......
      if(traitement_n_actif)
      {
        traitement_n(...);
      }
    }
    mais j ai peur que tous ces test a effectuer ne ralentissent le code

    ou alors l autre alternative que je vois est la suivante:
    tous les traitements implementent une interface commune etant donne qu ils utilisent les memes entree
    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
     
    constructeur(....)
    {
      // m_traitements est un vecteur de traitement membre de la classe
      if(traitement_1_actif)
      {
        m_traitements.push_back(traitement_1);
      }
      .......
      if(traitement_n_actif)
      {
        m_traitements.push_back(traitement_n);
      }
    }
     
    void method(....)
    {
      // ApplyTraitement est un objet fonction permettant de faire passer les donnees aux traitements du vector
      for_each(m_traitements.begin(),m_traitements.end(),applyTraitement(...));
    }
    J ai tendance a trouver la deuxieme solution plus elegante mais ce que je cherche avant tout c est l efficacite en terme de temps d execution...
    selon vous y en a t il une meilleure que l autre ? ou voyez vous un autre moyen plus efficace ?

  2. #162
    Membre expérimenté
    Avatar de FloMo
    Homme Profil pro
    Freelance iOS
    Inscrit en
    Juillet 2004
    Messages
    726
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Deux Sèvres (Poitou Charente)

    Informations professionnelles :
    Activité : Freelance iOS
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Juillet 2004
    Messages : 726
    Points : 1 511
    Points
    1 511
    Par défaut
    Personnellement, en matière d'optimisation, en plus des règles traditionnelles, j'utilise une bibliothèque qui me simplifie grandement la vie et est très performante : QT4.
    En effet, j'ai moins de code à écrire, donc moins de risque de perte de performances. L'API est très complète. Il y a un designer qui produit du code relativement propre qui me permet de faire des interfaces rapidement avec d'excellentes performances.
    A cela s'ajoute le fait que la gestion du multi-threading est particulièrement efficace, ce qui n'est pas négligeable en matière de performances.

    En gros : une bonne API, du code léger mais efficace et le tour est joué.
    "Il est plus facile de décomposer un problème en ses éléments, forcément plus simples, que de le traiter en sa totalité." (R. Descartes)

    Freelance iOS

  3. #163
    Membre éprouvé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Septembre 2006
    Messages
    519
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 30
    Localisation : Suisse

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Septembre 2006
    Messages : 519
    Points : 1 104
    Points
    1 104
    Par défaut
    Citation Envoyé par LeGreg
    les operateurs binaires operent sur les representations binaires
    des nombres. Point.
    Attention, il ne faut surtout pas confondre "opérateur binaire" et "opérateur agissant sur la représentation binaire" !
    Par exemple, ~ est un "opérateur agissant sur la représentation binaire" mais est unaire car ne prend qu'une opérande.
    En revanche, * et / sont binaires car ils prennent deux opérandes.

  4. #164
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Mai 2005
    Messages
    46
    Détails du profil
    Informations personnelles :
    Âge : 33
    Localisation : France

    Informations forums :
    Inscription : Mai 2005
    Messages : 46
    Points : 34
    Points
    34
    Par défaut
    Salut tout le monde,
    J'ai vu dans les premières pages qu'il fallait régulièrement bencher son code, mais vous le faites comment?
    Avec un clock() ?
    Merci

  5. #165
    Rédacteur
    Avatar de Bakura
    Homme Profil pro
    Étudiant
    Inscrit en
    Septembre 2005
    Messages
    1 386
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Septembre 2005
    Messages : 1 386
    Points : 2 640
    Points
    2 640
    Par défaut
    J'aurais une petite question :

    quelle différence entre int x (65) et int x = 65 ?

    Est-ce que ça a le même effet que ça :

    MaClasse:MaClasse ()
    : x (65) <---- Ca ?
    {
    }

    J'autre part, j'ai vu sur les papiers du prochain standard une rvalue référence, qui permettrait de faire ça :

    MaClasse && operator + (MaClasse obj1, MaClasse obj2)
    {
    return MaClasse (obj1.x + obj2.x, obj1.y + obj2.y);
    }

    Sans l'appel à un constructeur de copie ? Comme ça se fera internement (ça se dit ?). Provoquera t'il une amélioration des perfs que ce qui se passe actuellement (car d'après ce que j'ai compris, dans les cas comme ci-dessus, le compilo utilise l'optimisation RVO qui annule un peu cette surcharge ?

  6. #166
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 612
    Points : 30 612
    Points
    30 612
    Par défaut
    Salut,

    Pour les types de base ((unsigned)char, (unsigned) int, (unsigned) float, (unsigned) double etc), il n'y a pas de différence entre le fait d'utiliser la liste d'initialisation et celui de faire l'initialisation dans le corps du constructeur.

    Par contre, là où la différence apparait, c'est dans le cadre où le membre à initialiser est une classe ou une structure.

    En effet, en mettant que l'on aie une classe du genre de
    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
     
    class Membre
    {
        public:
            Membre(){}
            Membre(int i, float j)
            {
                /* ici, ca ne change pas grand chose */
                _i=i;
                _j=j;
            }
            void SetI(int i){_i=i;}
            void SetJ(float j){_j=j;}
            int GetI(){return _i;}
            float GetJ(){return _j;}
        private:
            int _i;
            float _j;
    };
    qui doit servir de membre dans la classe
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    class MaClasse
    {
        public:
            MaClasse(Membre& m);
            MaClasse(int i, float j);
           /*...*/
        private:
            Membre mem;
    };
    Le fait d'utiliser la liste d'initialisation apportera un gain de temps sous la forme de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    MaClasse::MaClasse(Membre& m):mem(m){}/* utilise
                                           * Membre::Membre(Membre&)
                                           */
    /* ou */
    MaClasse::MaClasse(int i, float j):mem(i,j){}/* utilise
                                                  * Membre::Membre(int i, float j)
                                                  */
    par rapport aux constructeurs sous les formes de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    MaClasse::MaClasse(Membre& m) /* utilise Membre::Membre() */
    {
        mem.SetI(m.GetI());/* il faut encore initialiser les valeurs de mem */
        mem.SetJ(m.GetJ());
    }
    /* ou */
    MaClasse::MaClass(int i; float j)/* utilise Membre::Membre() */
    {
        mem.SetI(i);/* il faut encore initialiser les valeurs de mem */
        mem.SetJ(j);
    }
    pour la simple raison que, les versions utilisant les liste d'initialisation se contenteront de l'appel du constructeur qui va bien selon le cas (par copie, ou en fournissant les valeurs nécessaire) alors que les autres versions vont:
    • Utiliser des valeurs par défaut pour le constructeur (généralement 0 pour _i et 0.0f pour _j dans l'exemple)
    • devoir assigner, pour chacun des membre de la classe membre (ici _i et _j) la valeur que l'on veut leur donner
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  7. #167
    Expert confirmé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Décembre 2003
    Messages
    3 549
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Décembre 2003
    Messages : 3 549
    Points : 4 625
    Points
    4 625
    Par défaut
    Pour les types de base ((unsigned)char, (unsigned) int, (unsigned) float, (unsigned) double etc), il n'y a pas de différence entre le fait d'utiliser la liste d'initialisation et celui de faire l'initialisation dans le corps du constructeur.
    C'est faux.
    Si le type est construit avec new, alors toutes ses variables membres qui sont des types de base seront initialisés à 0.
    Boost ftw

  8. #168
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 612
    Points : 30 612
    Points
    30 612
    Par défaut
    Citation Envoyé par loufoque
    C'est faux.
    Si le type est construit avec new, alors toutes ses variables membres qui sont des types de base seront initialisés à 0.
    Heuuu, faut il rappeler que le sujet et "de la rapidité du code", et que ton intervention n'a donc pas de sens de ce point de vue.

    Mon intervention étant à prendre dans le sens que j'ai expliqué: si le membre est d'un type primitif, il n'y aura pas de différence du point de vue de la rapidité d'exécution entre le fait d'utiliser une liste d'initialisation ou non. Par contre, si l'on veut initialiser un membre qui n'est pas strictement un type primitif, ce sera plus rapide d'exécution d'utiliser la liste d'initialisation, et sur ce coup là, rien n'est faux
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  9. #169
    Expert confirmé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Décembre 2003
    Messages
    3 549
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Décembre 2003
    Messages : 3 549
    Points : 4 625
    Points
    4 625
    Par défaut
    si le membre est d'un type primitif, il n'y aura pas de différence du point de vue de la rapidité d'exécution entre le fait d'utiliser une liste d'initialisation ou non
    Je viens pourtant de t'expliquer que non.
    Avec ton code, par exemple, _i et _j peuvent d'abord être initialisées à 0 avant que les valeurs i et j y soient assignées.
    Alors que si tu utilisais les listes d'initialisations, _i et _j seraient directement initialisées à la valeur voulue.

    Par contre, si l'on veut initialiser un membre qui n'est pas strictement un type primitif, ce sera plus rapide d'exécution d'utiliser la liste d'initialisation, et sur ce coup là, rien n'est faux
    Ce n'est pas qu'une question de rapidité, c'est aussi une question de sémantique. Initialiser une variable ce n'est pas la même chose que d'assigner une valeur à une variable.
    De plus, toutes les variables ne peuvent pas nécessairement s'initialiser par défaut.
    Boost ftw

  10. #170
    Rédacteur

    Avatar de Matthieu Brucher
    Profil pro
    Développeur HPC
    Inscrit en
    Juillet 2005
    Messages
    9 810
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France, Pyrénées Atlantiques (Aquitaine)

    Informations professionnelles :
    Activité : Développeur HPC
    Secteur : Industrie

    Informations forums :
    Inscription : Juillet 2005
    Messages : 9 810
    Points : 20 970
    Points
    20 970
    Par défaut
    Citation Envoyé par loufoque
    C'est faux.
    Si le type est construit avec new, alors toutes ses variables membres qui sont des types de base seront initialisés à 0.
    Ca aussi, c'est faux.
    Le constructeur par défaut est appelé, et les types de bases ne sont initialisés à 0 qu'en mode debug.

  11. #171
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 518
    Points
    41 518
    Par défaut
    En mode Debug sous quel plate-forme ?
    C'est totalement contre-productif d'initialiser à zéro en mode Debug. Des valeurs telles que 0xCCCCCCCC sont plus utiles...
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  12. #172
    Rédacteur

    Avatar de Matthieu Brucher
    Profil pro
    Développeur HPC
    Inscrit en
    Juillet 2005
    Messages
    9 810
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France, Pyrénées Atlantiques (Aquitaine)

    Informations professionnelles :
    Activité : Développeur HPC
    Secteur : Industrie

    Informations forums :
    Inscription : Juillet 2005
    Messages : 9 810
    Points : 20 970
    Points
    20 970
    Par défaut
    Avec GCC par exemple, même chose pour Visual, ...

  13. #173
    Expert confirmé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Décembre 2003
    Messages
    3 549
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Décembre 2003
    Messages : 3 549
    Points : 4 625
    Points
    4 625
    Par défaut
    les types de bases ne sont initialisés à 0 qu'en mode debug
    C'est quand même fou.
    Je vais donc répéter pour une troisième fois, et citer le standard pour ceux qui ne veulent pas me croire.

    Les types de base sont initialisés à 0 quand on utilise new.
    Par exemple
    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
    #include <iostream>
     
    struct Foo
    {
    	int value;
    };
     
    int main()
    {
    	Foo v1;
    	int t;
    	Foo* v2 = new(&t) Foo();
    	Foo* v3 = new Foo();
     
    	std::cout << v1.value << std::endl;
    	std::cout << v2->value << std::endl;
    	std::cout << v3->value << std::endl;
     
    	delete v3;
    }
    affichera dans le premier cas une valeur indéfinie, et dans les deux autres 0.

    Voir paragraphe 5.3/16 de N2284.
    Boost ftw

  14. #174
    Rédacteur

    Avatar de Matthieu Brucher
    Profil pro
    Développeur HPC
    Inscrit en
    Juillet 2005
    Messages
    9 810
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France, Pyrénées Atlantiques (Aquitaine)

    Informations professionnelles :
    Activité : Développeur HPC
    Secteur : Industrie

    Informations forums :
    Inscription : Juillet 2005
    Messages : 9 810
    Points : 20 970
    Points
    20 970
    Par défaut
    Encore pire dans ce cas.

  15. #175
    Expert éminent

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Points : 6 911
    Points
    6 911
    Par défaut
    Citation Envoyé par loufoque
    Pour les types de base ((unsigned)char, (unsigned) int, (unsigned) float, (unsigned) double etc), il n'y a pas de différence entre le fait d'utiliser la liste d'initialisation et celui de faire l'initialisation dans le corps du constructeur.
    C'est faux.
    Si le type est construit avec new, alors toutes ses variables membres qui sont des types de base seront initialisés à 0.
    Tu confonds. Si il y a des constructeurs -- et si c'est pas un POD, il en faut, éventuellement généré automatiquement -- new va appeller un de ceux-ci, et dans ce cas les membres d'un type de base non présents dans la liste d'initialisation ne sont pas initialisés. Pour les POD sans constructeur, effectivement new fait une initialisation à 0.
    Les MP ne sont pas là pour les questions techniques, les forums sont là pour ça.

  16. #176
    Expert éminent sénior

    Homme Profil pro
    pdg
    Inscrit en
    Juin 2003
    Messages
    5 749
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : pdg

    Informations forums :
    Inscription : Juin 2003
    Messages : 5 749
    Points : 10 666
    Points
    10 666
    Billets dans le blog
    3
    Par défaut
    Je crois que dans le cas de VC++ c'est le cas depuis la version 2005 seulement.
    Sinon je viens d'apprendre aujourd'hui que les types de bases étaient initialisés à zéro s'ils étaient statiques.

  17. #177
    Expert éminent

    Homme Profil pro
    Ingénieur systèmes et réseaux
    Inscrit en
    Février 2007
    Messages
    4 253
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur systèmes et réseaux
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Février 2007
    Messages : 4 253
    Points : 7 618
    Points
    7 618
    Billets dans le blog
    3
    Par défaut
    Visual Studio suit (pour une fois) les recommendations et ne fait (par défaut) aucune initialisation lors d'un 'new' d'un objet avec constructeur, à part celle indiquée dans la liste d'initialisation.

    Il existe un flag du compilateur, qui peut le forcer à remplir la mémoire par (de mémoire) 0xCD, flag utilisé en mode "debug", et qui permet de trouver bien vite les bugs (bien plus vite qu'une initilalisation à 0 en tout cas).

    Il se peut qu'en mode "release" l'initialisation par affectation dans le constructeur soit identique à celle par la liste d'initialisation, j'avoue n'avoir jamais eu à le vérifier (pas encore eu de profiler me montrant du doigt un constructeur à optimiser).
    N'oubliez pas de cliquer sur mais aussi sur si un commentaire vous a été utile !
    Et surtout

  18. #178
    Expert éminent sénior

    Homme Profil pro
    pdg
    Inscrit en
    Juin 2003
    Messages
    5 749
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : pdg

    Informations forums :
    Inscription : Juin 2003
    Messages : 5 749
    Points : 10 666
    Points
    10 666
    Billets dans le blog
    3
    Par défaut
    En cherchant des infos la dessus, je découvre que, d'apres la MSDN, le standard fait une distinction entre:
    et
    l'initialisation de *i a 0 ne se ferait que dans le 2eme cas...
    http://msdn2.microsoft.com/en-us/lib...y9(VS.80).aspx



    VC++ 2003 respectait cela uniquement pour les types scalaires. VC++ 2005 le respecte aussi pour les classes:
    http://msdn2.microsoft.com/en-us/lib...8k(VS.80).aspx

  19. #179
    Rédacteur
    Avatar de Bakura
    Homme Profil pro
    Étudiant
    Inscrit en
    Septembre 2005
    Messages
    1 386
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Septembre 2005
    Messages : 1 386
    Points : 2 640
    Points
    2 640
    Par défaut
    Aurélien > De manière analogue, si on écrit int test (), test semble aussi avoir une valeur par défaut (chez moi c'est 1).

  20. #180
    Rédacteur
    Avatar de Laurent Gomila
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    10 651
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 10 651
    Points : 15 920
    Points
    15 920
    Par défaut
    Si tu écris int test(), tu déclareras une fonction renvoyant un int, pas une variable

Discussions similaires

  1. Réponses: 1
    Dernier message: 31/08/2014, 17h52
  2. Optimiser rapidité code
    Par bobosh dans le forum VBA Access
    Réponses: 2
    Dernier message: 28/08/2008, 16h12
  3. Optimisation code pour gagner en rapidité
    Par polodu84 dans le forum MATLAB
    Réponses: 2
    Dernier message: 05/03/2008, 15h32
  4. requete QBE / requete code : rapidité et index
    Par LostIN dans le forum Requêtes et SQL.
    Réponses: 11
    Dernier message: 05/07/2006, 08h54
  5. [rapidité du code] Mise a jour a partir d'un TQuery.
    Par goethe dans le forum Bases de données
    Réponses: 4
    Dernier message: 27/10/2004, 09h01

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