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

C++ Discussion :

Class Matrix : pointeur ou vector pour le stockage des données


Sujet :

C++

  1. #1
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Mai 2013
    Messages
    113
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mai 2013
    Messages : 113
    Points : 50
    Points
    50
    Par défaut Class Matrix : pointeur ou vector pour le stockage des données
    Salut à tous,

    je me pose une question concernant la création d'une classe Matrix en c++. Du point de vue des performances, est il préférable d'utiliser un pointeur ou un vector pour le stockage des données ? Et bien sur quelle en est la raison ?

    Je sais que le sujet de la class Matrix est largement documenté mais je n'est pas trouvé de réponse à cette question puisqu'on trouve régulièrement les deux constructions.

    Merci d'avance pour vos réponses

  2. #2
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 189
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

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

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 189
    Points : 17 141
    Points
    17 141
    Par défaut
    c'est pas un "pointeur", mais un tableau.
    Si ta matrice est d'une taille connue à la compilation (et donc fixe), tu peux opter pour le tableau.
    Si ce n'est pas le cas, tu auras besoin d'un vector.

    Par ailleurs, nous avons deux articles sur les matrices dans notre FAQ, (dans fonctions > opérateurs)
    Elles seront à minima un bon rappel.

    L'idée est d'avoir une interface uniquement basée sur operator(), pour pouvoir masquer ces détails internes.
    Mes principes de bases du codeur qui veut pouvoir dormir:
    • Une variable de moins est une source d'erreur en moins.
    • Un pointeur de moins est une montagne d'erreurs en moins.
    • Un copier-coller, ça doit se justifier... Deux, c'est un de trop.
    • jamais signifie "sauf si j'ai passé trois jours à prouver que je peux".
    • La plus sotte des questions est celle qu'on ne pose pas.
    Pour faire des graphes, essayez yEd.
    le ter nel est le titre porté par un de mes personnages de jeu de rôle

  3. #3
    Expert éminent sénior
    Avatar de Luc Hermitte
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2003
    Messages
    5 275
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Août 2003
    Messages : 5 275
    Points : 10 985
    Points
    10 985
    Par défaut
    D'un point de vue perfs, il est fortement recommandé d'utiliser une des libs déjà disponible comme p.ex. Eigen.

    Après, avec le vecteur, tu paieras une 0-initialisation non nécessaire.
    De fait, un tableau dynamique sera plus pertinent pour des raisons de perfs. Mais cela implique soit de passer par un unique_ptr<T[]> (syntaxe non garantie) et d'écrire copie et affectation, soit d'utiliser un tableau dynamique à la main, ce qui implique de se palucher à la main les 5 opérations qui vont bien (copie, affectation, déplacement (constructeur et opérateur), et destructeur).

    Le vecteur est très bien pour le premier TD d'écriture d'une matrice, ou pour du code de production qui n'a pas des besoins micro-optimisés côté perfs. Et surtout c'est très bien pour avoir du code robuste. Le débutant tend à ne pas savoir ce qu'il doit écrire, quand, ni comment en termes de copies -- et oui, les réponses sont dans la FAQ.
    Blog|FAQ C++|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS|Bons livres sur le C++
    Les MP ne sont pas une hotline. Je ne réponds à aucune question technique par le biais de ce média. Et de toutes façons, ma BAL sur dvpz est pleine...

  4. #4
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Mai 2013
    Messages
    113
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mai 2013
    Messages : 113
    Points : 50
    Points
    50
    Par défaut
    Bonjour leternel et merci pour ta réponse,

    je vais préciser un peu ma question. Est il plus performant de

    -> Définir un pointeur membre d'une classe Matrix contenant les données de la matrice

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    //Dans le .hpp
    double *_data;
    Puis allouer dynamiquement la mémoire dans le constructeur

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    //Dans le .cpp
    _data = new double[_i*_j];     //Avec _i et _j les variables membres correspondant au nombre de ligne et au nombre de colonne
    -> Définir un vector membre d'une classe Matrix contenant les données de la matrice

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    //Dans le .hpp
    vector<double> _data;
    Puis utiliser la fonction resize dans le constructeur

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    //Dans le .cpp
    _data.resize(_i*_j);

    Ma question ne concerne pas la déclaration de tableau statique ou encore la surcharge de l'opérateur operator().

    Désolé de ne pas m'être fait comprendre dès mon premier post.

  5. #5
    Expert éminent sénior
    Avatar de Luc Hermitte
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2003
    Messages
    5 275
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Août 2003
    Messages : 5 275
    Points : 10 985
    Points
    10 985
    Par défaut
    Citation Envoyé par kipgon Voir le message
    Puis utiliser la fonction resize dans le constructeur
    ???
    La liste d'initialisation permet d'appeler le bon constructeur directement. Tu ne veux pas appeler resize() sur l'attribut d'un objet dans son constructeur.
    Blog|FAQ C++|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS|Bons livres sur le C++
    Les MP ne sont pas une hotline. Je ne réponds à aucune question technique par le biais de ce média. Et de toutes façons, ma BAL sur dvpz est pleine...

  6. #6
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Mai 2013
    Messages
    113
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mai 2013
    Messages : 113
    Points : 50
    Points
    50
    Par défaut
    Salut Luc Hermitte,

    j'ai poster ma réponse sans voir ton post.

    Je me doutais un peu que le tableau dynamique serait plus performant. Cela dit tu as raison si les performances sont recherchées autant utiliser un bibliothèque, je me posais cette question pour bien comprendre les choses.

    Qu'appelles tu une 0-initialisation ? Initialiser l'ensemble des données à 0 ? Si c'est le cas, n'est ce pas une bonne chose ? J'avoue que j'aurais tout de même initialisé mon tableau dynamique dans le constructeur .

    Par curiosité toujours, quelle sont les optimisations qui sont faites dans les bibliothèques ? Connaissez vous de la documentation sur cette question ?

  7. #7
    Expert éminent sénior
    Avatar de Luc Hermitte
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2003
    Messages
    5 275
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Août 2003
    Messages : 5 275
    Points : 10 985
    Points
    10 985
    Par défaut
    La 0-initialisation peut être intéressante dans certains cas, mais quand on écrit A = M * N * V + C; il serait ridicule de payer une 0-initialisation sur chaque temporaire construit dans l'histoire.

    Pour les optims, la plus ancienne est l'élimination des temporaires par expression-template (c'est un mot clé, cf le vieux Blitz++). Avec le C++11 on a encore d'autres moyens pour éliminer des copies.

    Après, les bibliothèques dédiées vont parfois exploiter des optimisations plus bas niveau sur comment les boucles sont écrites, l'exploitation de spécificités des architectures, les multi-coeurs, etc. Les BLAS ont longtemps été la référence en FORTRAN. Le wiki d'Eigen me semble contenir pas mal d'infos sympas. (des benchs par là: http://eigen.tuxfamily.org/index.php?title=Benchmark)
    Blog|FAQ C++|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS|Bons livres sur le C++
    Les MP ne sont pas une hotline. Je ne réponds à aucune question technique par le biais de ce média. Et de toutes façons, ma BAL sur dvpz est pleine...

  8. #8
    Expert éminent sénior
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2005
    Messages
    5 071
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Février 2005
    Messages : 5 071
    Points : 12 116
    Points
    12 116
    Par défaut
    Les optimisations dans l'absolu, c'est un non-sens.
    On optimise pour un mode d'utilisation.

  9. #9
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Mai 2013
    Messages
    113
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mai 2013
    Messages : 113
    Points : 50
    Points
    50
    Par défaut
    Merci pour toute ces informations, je vais aller fouiller sur le lien que tu m'as donné.

    Concernant les actions réalisées par le constructeurs, écrire à l'intérieur du constructeur :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    _data = new double[_i*_j];    // Est correct (dans le cas de l'utilisation d'un pointeur)
    Mais écrire à l'intérieur du constructeur :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    _data.resize(_i*_j);      //N'est pas correct (dans le cas de l'utilisation d'un vector)
    Est ce que j'ai bien compris ? (Désolé si c'est une question bête)

  10. #10
    Expert éminent sénior
    Avatar de Luc Hermitte
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2003
    Messages
    5 275
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Août 2003
    Messages : 5 275
    Points : 10 985
    Points
    10 985
    Par défaut
    Tu ne connais visiblement pas les listes d'initialisation.

    On écrira:
    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
    // à la mano, style C++
    template <typename T>
    Matrix<T>::Matrix(size_t N_, size_t M_)
    : m_buffer(new T[N_ * M_])
    , m_N(N_)
    , m_M(M_)
    {}
     
    // à la mano, style autres langages
    template <typename T>
    Matrix<T>::Matrix(size_t N_, size_t M_)
    {
        m_buffer = new T[N_ * M_]);
        m_N = N_;
        m_M = M_;
    }
     
    // avec des vecteurs
    template <typename T>
    Matrix<T>::Matrix(size_t N_, size_t M_)
    : m_buffer(N_ * M_)
    , m_N(N_)
    , m_M(M_)
    {}
    Bref. Ouvre un cours au chapitre des listes d'initialisation.
    Blog|FAQ C++|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS|Bons livres sur le C++
    Les MP ne sont pas une hotline. Je ne réponds à aucune question technique par le biais de ce média. Et de toutes façons, ma BAL sur dvpz est pleine...

  11. #11
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Mai 2013
    Messages
    113
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mai 2013
    Messages : 113
    Points : 50
    Points
    50
    Par défaut
    En réalité je connais les listes d'initialisations mais je m'en sert uniquement pour attribuer des valeurs. Je n'avais jamais utilisé new dans une liste d'initialisation.

    Cela dit je n'ai pas une formation solide en c++, je m'en vais donc de ce pas "ouvrir un cours au chapitre des listes d'initialisations" .

    Merci pour ton aide Luc Hermitte et à bientôt.

  12. #12
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 115
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 115
    Points : 32 967
    Points
    32 967
    Billets dans le blog
    4
    Par défaut
    Citation Envoyé par kipgon Voir le message
    En réalité je connais les listes d'initialisations mais je m'en sert uniquement pour attribuer des valeurs. Je n'avais jamais utilisé new dans une liste d'initialisation.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    _data = new double[_i*_j];
    Je suis à peu près sur que ce code attribue la valeur new double[_i*_j]; à _data.

    vector::resize appel un constructeur par copie et initialise chaque élément (cf sa doc). Pour faire mieux on peut reserve puis push_back.
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  13. #13
    Expert éminent sénior
    Avatar de Luc Hermitte
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2003
    Messages
    5 275
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Août 2003
    Messages : 5 275
    Points : 10 985
    Points
    10 985
    Par défaut
    ???
    resize est appelé après un constructeur par défaut puis construit/0-initialise chaque valeur à un nombre.
    L'appel direct au bon constructeur squizze la construction par défaut qui ne sert à rien.
    reserve + push_back en boucle va quand même payer à chaque itération un test pour savoir s'il faut se redimensionner, mais il évite la 0-initialisation (/construction par défaut dans le cas plus général).
    Blog|FAQ C++|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS|Bons livres sur le C++
    Les MP ne sont pas une hotline. Je ne réponds à aucune question technique par le biais de ce média. Et de toutes façons, ma BAL sur dvpz est pleine...

  14. #14
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Mai 2013
    Messages
    113
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mai 2013
    Messages : 113
    Points : 50
    Points
    50
    Par défaut
    Citation Envoyé par Bousk Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    _data = new double[_i*_j];
    Je suis à peu près sur que ce code attribue la valeur new double[_i*_j]; à _data.
    ^^ tu as tout à fait raison bousk.

    Pour un amateur comme moi cela "alloue de la mémoire et non une valeur" , même si en effet "allouer de la mémoire" revient à "donner une valeur à un pointeur" !

    Pour le dire autrement c'était moins évident pour moi

    Mais merci pour ta remarque (+1)

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

Discussions similaires

  1. Réponses: 3
    Dernier message: 10/04/2015, 15h40
  2. 3 solutions pour le stockage des données
    Par loic20h28 dans le forum UML
    Réponses: 53
    Dernier message: 21/01/2009, 12h15
  3. Comparatif des SGBDR pour le stockage des BLOBs
    Par rnan dans le forum Décisions SGBD
    Réponses: 9
    Dernier message: 10/08/2007, 13h05
  4. question théorique sur le stockage des données
    Par jp_rennes dans le forum Administration
    Réponses: 1
    Dernier message: 18/09/2006, 18h28
  5. [HTML] Tableau pour l'enregistrement des données
    Par ghyosmik dans le forum Balisage (X)HTML et validation W3C
    Réponses: 13
    Dernier message: 01/11/2005, 15h28

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