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 C++ Discussion :

Implémentation pointeur unique.


Sujet :

Langage C++

  1. #1
    Membre à l'essai
    Profil pro
    Inscrit en
    Mai 2007
    Messages
    40
    Détails du profil
    Informations personnelles :
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations forums :
    Inscription : Mai 2007
    Messages : 40
    Points : 19
    Points
    19
    Par défaut Implémentation pointeur unique.
    Bonjour,

    Je suis en train de me former sur l'utilisation du pointeur unique (unique_ptr).
    Ainsi, je voudrais implémenter ce type de smart pointeur dans un certain algorithme qui initialement utilise des pointeurs bruts classiques et fonctionne très bien.

    Mais je rencontre des problèmes dans l'utilisation du pointeur unique.

    Afin de ne pas embrouiller les lecteurs de mon message par un code compliqué, j'ai pu reproduire le problème actuel dans un petit programme que je vous présente ci-dessous avec ses commentaires.

    Ce programme fonctionne très bien tant que je mets en commentaire les lignes 49 et 52.
    Dans ces lignes j’essaye simplement de transférer le contenu d’une case de tableau (contenant un pointeur) dans un pointeur de la même nature.
    Cela fonctionne avec les pointeurs bruts, mais j’obtiens des erreurs de compilation avec le unique_ptr :.


    Merci par avance.

    Cordialement

    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
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
     
    void testuniqueptr(void)
     
    {
     
        #define TAILLEMAX 10000 // Taille maximale du tableau de pointeurs de float à allouer.
     
        int Taille,k;
        int Taillemax(TAILLEMAX);
        typedef float *ADDFLOAT; // ADDFLOAT représente donc un pointeur sur float.
     
        string message("Taille du vecteur de float :");
     
        while (oglirnombre(Taille, message)) {
     
            if (Taille<=0 || Taille>Taillemax) continue;
     
            // Allocation dynamique d'un tableau de N=Taille ADDFLOAT :
     
            unique_ptr<ADDFLOAT[]> panier(new ADDFLOAT[Taille]); // panier est donc un tableau de ADDFLOAT. Ainsi, pour chaque k, panier[k] sera un pointeur sur float.
     
            for (k=0; k<Taille; k++ ) {
     
                // 1. On teste l'affectation à nullptr de panier[k] :
     
                panier[k]=nullptr;
     
                // 2. On alloue dans point un float, donc point est du même type que panier[k] (c'est à dire un pointeur sur float) :
     
                unique_ptr<float> point(new float);
     
                // 3. On assigne une valeur (en l'occurrence k), à l'adresse pointée par point, histoire de présenter un résultat contrôlable :
     
                (*point)=(float)k;
     
                // 4. On assigne point qui est un pointeur(valide) sur float, à panier[k], lui même pointeur sur float . Tout se passe bien, y compris à l'exécution :
     
                panier[k]=point.get();
     
                // 5. Inversement, on essaye d'assigner la valeur de panier[k] (pointeur sur float) à point (également pointeur sur float). C'est ici que ça se gâte :
     
                // 5.1 - 1er version (sans get()) :ERREUR compilation: "no match for operator= in point = panier.std::unique_ptr<_Tp ..."
     
                point=panier[k];
     
     
                // 5.2 - 2eme version (avec get()) :ERREUR compilation: "error: request for member 'get' in panier.std::unique_ptr<_Tp [], ..."
     
                point=panier[k].get();
     
     
                // On affiche les contenus de tous ces pointeurs pour vérification. Tout est ok à l'exécution lorsque les instructions 5.1 et 5.2 sont désactivées :
     
                cout << "panier[" << k << "]= " << (*panier[k]) << " (*point)= " << *point << endl;
     
            }
     
        }
     
    }

  2. #2
    En attente de confirmation mail

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2004
    Messages
    1 391
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France, Doubs (Franche Comté)

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

    Informations forums :
    Inscription : Août 2004
    Messages : 1 391
    Points : 3 311
    Points
    3 311
    Par défaut
    Sans les numéros de ligne en dur, c'est mieux.

    J'ai regardé ton code, mais je ne comprends pas ce que tu veux faire. Il est cependant peu probable que tu ais besoin d'un std::unique_ptr<float*[]>. D'où la question, qu'est ce que tu veux faire ?

    Cependant, sans comprendre ce que tu fais, j'ai plutôt l'impression que c'est un std::vector<float> dont tu as besoin. Les meilleurs cas d'utilisation de std::unique_ptr que tu pourras trouver c'est, AMA, des std::vector<std::unique_ptr<Base>>Base est une classe de base d'une hiérarchie polymorphe.

  3. #3
    Membre à l'essai
    Profil pro
    Inscrit en
    Mai 2007
    Messages
    40
    Détails du profil
    Informations personnelles :
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations forums :
    Inscription : Mai 2007
    Messages : 40
    Points : 19
    Points
    19
    Par défaut
    Merci pour ta réponse,

    En fait le code que je présente, ne fait rien de particulier et n'a aucune logique.
    Il permet simplement de reproduire en l'isolant un problème que je rencontre dans la 'modernisation' d'un ancien algorithme de tri par ventilations qui fonctionne avec des pointeurs bruts.
    L'idée était de passer à l'unique_ptr pour éviter de gérer les delete dans la gestion de l'alloc dynamique que je fait dans mon algorithme.

    A ce stade, Je voudrais simplement comprendre pourquoi l'affectation de panier[k] à point ne fonctionne pas en lignes 44 ou 49.
    Et j'ai effectivement besoin de réaliser cette instruction dans mon algorithme.

    Pour le moment je préfère encore garder un tableaux plutôt que gérer un vector pour conserver la même structure que mon ancien algo. Mais dans une deuxième phase j'y réfléchirai.

  4. #4
    Membre chevronné Avatar de Ehonn
    Homme Profil pro
    Étudiant
    Inscrit en
    Février 2012
    Messages
    788
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France

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

    Informations forums :
    Inscription : Février 2012
    Messages : 788
    Points : 2 160
    Points
    2 160
    Par défaut
    Citation Envoyé par jcmic Voir le message
    En fait le code que je présente, ne fait rien de particulier et n'a aucune logique.
    Il permet simplement de reproduire en l'isolant un problème que je rencontre dans la 'modernisation' d'un ancien algorithme de tri par ventilations qui fonctionne avec des pointeurs bruts.
    L'idée était de passer à l'unique_ptr pour éviter de gérer les delete dans la gestion de l'alloc dynamique que je fait dans mon algorithme.
    Utilise tout simplement un std::vector<float> (?)
    std::unique_ptr est souvent nécessaire pour avoir le bon comportement vis-à-vis des fonctions virtual. As-tu besoin de ça ?

    Citation Envoyé par jcmic Voir le message
    Pour le moment je préfère encore garder un tableaux plutôt que gérer un vector pour conserver la même structure que mon ancien algo. Mais dans une deuxième phase j'y réfléchirai.
    Tu peux / dois utiliser des std::vector. Si tu ne veux pas modifier l'algo maintenant, tu peux utiliser la fonction membre .data() pour récupérer un truc à la C.

  5. #5
    Membre à l'essai
    Profil pro
    Inscrit en
    Mai 2007
    Messages
    40
    Détails du profil
    Informations personnelles :
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations forums :
    Inscription : Mai 2007
    Messages : 40
    Points : 19
    Points
    19
    Par défaut
    Non je n'utilise pas de fonction virtual dans cet algo.

    Je voulais utiliser un pointeur unique dans le but de ne pas gérer moi-même la désallocation mémoire (par une procédure adaptée à l'algorithme et qui utilise donc delete à la base ).
    Comme cette procédure de désallocation (à la main) est couteuse en temps sur des tableaux et listes de grandes tailles, dégradant ainsi les performances de mon tri, je voulais simplement comparer à ce qu'il se passerait si le système lui-même gérait cette désallocation.
    D'où l'idée du pointeur unique.

  6. #6
    Membre chevronné Avatar de Ehonn
    Homme Profil pro
    Étudiant
    Inscrit en
    Février 2012
    Messages
    788
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France

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

    Informations forums :
    Inscription : Février 2012
    Messages : 788
    Points : 2 160
    Points
    2 160
    Par défaut
    J'ai une trrès bonne nouvelle pour toi alors
    Le compilateur le fait pour toi en fait. Comme illustré dans cet 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
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    // g++ -Wall -Wextra -Wconversion -Wsign-conversion -std=c++11 -pedantic -fopenmp main.cpp -o main && ./main
    // g++ -Wall -Wextra -Wconversion -Wsign-conversion -std=c++98 -pedantic -fopenmp main.cpp -o main && ./main
    // g++ -Wall -Wextra -Wconversion -Wsign-conversion -std=c++98 -pedantic main.cpp -o main && valgrind ./main
     
    #include <iostream>
    #include <vector>
    #include <string>
     
     
    int main()
    {
    	// Bloc
    	{
    		std::vector<std::string> v;
    		v.push_back("Le");
    		v.push_back("destructeur");
    		v.push_back("des");
    		v.push_back("objets");
    		v.push_back("alloués");
    		v.push_back("sur");
    		v.push_back("la");
    		v.push_back("pile");
    		v.push_back("est");
    		v.push_back("appelé");
    		v.push_back("automatiquement");
    		v.push_back("par");
    		v.push_back("le");
    		v.push_back("compilateur");
    		v.push_back("à");
    		v.push_back("la");
    		v.push_back("fin");
    		v.push_back("du");
    		v.push_back("bloc");
    		v.push_back("=)");
     
    		for (std::size_t i = 0; i < v.size(); ++i)
    		{
    			std::cout << v[i] << " ";
    		}
    		std::cout << std::endl;
    	}
     
    	return 0;
    }
    Et voilà la sortie avec Valgrind :
    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
    $ g++ -Wall -Wextra -Wconversion -Wsign-conversion -std=c++98 -pedantic main.cpp -o main && valgrind ./main
    //==6127== Memcheck, a memory error detector
    //==6127== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
    //==6127== Using Valgrind-3.10.0 and LibVEX; rerun with -h for copyright info
    //==6127== Command: ./main
    //==6127== 
    Le destructeur des objets alloués sur la pile est appelé automatiquement par le compilateur à la fin du bloc =) 
    //==6127== 
    //==6127== HEAP SUMMARY:
    //==6127==     in use at exit: 0 bytes in 0 blocks
    //==6127==   total heap usage: 26 allocs, 26 frees, 1,098 bytes allocated
    //==6127== 
    //==6127== All heap blocks were freed -- no leaks are possible
    //==6127== 
    //==6127== For counts of detected and suppressed errors, rerun with: -v
    //==6127== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

  7. #7
    En attente de confirmation mail

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2004
    Messages
    1 391
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France, Doubs (Franche Comté)

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

    Informations forums :
    Inscription : Août 2004
    Messages : 1 391
    Points : 3 311
    Points
    3 311
    Par défaut
    Tu pourrais présenter l'algo directement ? Un code minimal qui reproduit le problème, c'est bien, mais faut quand même qu'il rend compte un minimum de la situation.

    Pour les erreurs (que tu aurais pu écrire en entier d'ailleurs) :
    5.1. : panier[k] est un float*, tu ne peux pas l'affecter à un unique_ptr<float>.
    5.2. : Comme c'est un float* il n'a pas de fonction membre get.

    Vouloir automatiser la gestion de la mémoire c'est très bien, mais ce n'est pas systématiquement synonyme d'utiliser un unique_ptr. Utiliser un vector c'est aussi automatiser la gestion de la mémoire.

  8. #8
    Membre à l'essai
    Profil pro
    Inscrit en
    Mai 2007
    Messages
    40
    Détails du profil
    Informations personnelles :
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations forums :
    Inscription : Mai 2007
    Messages : 40
    Points : 19
    Points
    19
    Par défaut
    Merci pour ces précisions. L'affectation n'est donc pas possible dans ce sens.

    Je pense que l'utilisation d'un pointeur unique n'est sans doute pas judicieuse dans mon cas. Je verrai plus tard pour utiliser un vector.
    Si j'ai le temps je vous enverrai le code complet de cet algorithme de tri avec des explications.

    Pour faire court, je dois trier N clefs par un algorithme appellé bucket sort. (on le trouve dans la littérature sur les tris).

    Le principe de l'algorithme consiste à répartir ces clefs (en fait leur adresses), via une fonction mathématique de répartition uniforme, dans des listes linéaires chainées distinctes.
    La fonction de répartition étant uniforme, les clefs se retrouvent donc déja équitablement réparties dans leurs listes et le gros du tri est déja réalisé, car toutes les clefs d'un panier donné sont plus petites que toutes celles du panier suivant.

    Ensuite je tri ces listes une par une (par un autre algo) et enfin je réaffecte les listes triées dans la table principale qui se retrouve ainsi triée.
    L'algorithme en lui-meme est trés rapide, mais perd beaucoup de temps à désallouer la mémoire des listes (paniers) une fois triées.

    En effet, les boucles successives de delete sur un grand nombre de données pénalise la performance globale.

    Pour trier 32 millions de clefs numériques en double précision, l'algo prend environ 13s sur mon ordi (core i7).

    Le meme algorithme qui trie une liste linéaire et non un tableau, met environ 7s car dans ce cas le tri s'effectue sur place, c'est à dire que les paniers (les sous-listes) sont gérés dans la liste elle-meme, donc pas de sous liste à creer,
    donc pas desallocation mémoire.

    On peut donc dire qu'environ la moitié du temps d'exécution est passé à allouer-désallouer la mémoire dans le cas du tri sur tableau.

Discussions similaires

  1. [Turbo Pascal] Allocation et désallocation de pointeurs dans une fonction
    Par neird dans le forum Turbo Pascal
    Réponses: 13
    Dernier message: 17/11/2002, 20h14
  2. djgpp et pointeurs far -2
    Par elvivo dans le forum Autres éditeurs
    Réponses: 16
    Dernier message: 29/07/2002, 22h43
  3. djgpp et pointeurs far
    Par elvivo dans le forum C
    Réponses: 2
    Dernier message: 13/07/2002, 00h44
  4. Réponses: 2
    Dernier message: 06/07/2002, 12h36
  5. Implémentation des fonctions mathématiques
    Par mat.M dans le forum Mathématiques
    Réponses: 9
    Dernier message: 17/06/2002, 16h19

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