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 :

Surcharge de l'opérateur new


Sujet :

C++

  1. #1
    Membre à l'essai
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2015
    Messages
    24
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 32
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mars 2015
    Messages : 24
    Points : 24
    Points
    24
    Par défaut Surcharge de l'opérateur new
    Bonjour,

    je suis actuellement en train de créer des pointeurs intelligents
    cependant lorsque je surcharge mon opérateur new (dans ma classe, pas globalement) je rencontre une erreur.
    Le compilateur me sort des erreurs car les attributs de ma classe ne sont pas static

    Voilà les parties qui ne fonctionnent pas :

    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
     
    template<typename Type>
    class Ptr_intelligent
    {
    	public:
    		Ptr_intelligent(); //constructeur par défaut
    		Ptr_intelligent(Type*); // constructeur par copie
    		Ptr_intelligent(const Ptr_intelligent<Type>&); //constructeur par copie
    		~Ptr_intelligent(); //destructeur
    		void * operator new(size_t);
     
    	private:
    		Type* ptr;
    		Compteur* cpt_ref;
    		allocateur<Type> a;
     
    };
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    template<typename Type>
    void * Ptr_intelligent<Type>::operator new (size_t taille)
    {
    	ptr = a.allouer(taille);
    	return ptr;
     
    }
    En surchargeant l'opérateur new on est obligé d'utiliser des membres static uniquement ?

    Merci

  2. #2
    Membre expert
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2011
    Messages
    739
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

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

    Informations forums :
    Inscription : Juin 2011
    Messages : 739
    Points : 3 627
    Points
    3 627
    Par défaut
    > En surchargeant l'opérateur new on est obligé d'utiliser des membres static uniquement ?

    Oui, car l'opérateur new s’applique avant la construction de l'objet, donc pas d'instance, donc static.

    S'il fallait surcharger new pour un pointeur intelligent, se serait plutôt : void * operator new(size_t) = delete. Parce qu'allouer dynamiquement un pointeur intelligent et se balader avec un pointeur cause toujours des problèmes de durée de vie et la fameuse question: qui est le propriétaire ?

    Pour construire une telle classe, les constructeurs sont largement suffisants (ne pas oublier le constructeur de mouvement, idem pour l'opérateur=).

    PS: un constructeur qui prend un T* pour le copier n'est à mon sens pas une bonne idée. Devenir propriétaire oui, prendre une référence et la copier, bof. Mais copier le pointeur, clairement non.
    PS2: pourquoi ne pas utiliser std::shared_ptr ?

  3. #3
    Membre à l'essai
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2015
    Messages
    24
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 32
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mars 2015
    Messages : 24
    Points : 24
    Points
    24
    Par défaut
    Merci pour la réponse.
    Pourquoi ne pas utiliser shared_ptr ? : Parce que le sujet de mon TP est justement de réaliser des pointeurs intelligents "maisons"
    mais je pense que je n'ai pas bien compris la situation.

    Donc je vais abandonner cette histoire de new et utiliser mes constructeurs uniquement : merci !

    Mais j'ai encore du mal à comprendre 2-3 trucs, comme par exemple pourquoi je peux déclarer :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    Ptr_intelligent<int> p;
    et faire :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    printf("%d %d \n",*p,p[50]);
    sans obtenir d'erreur ?

    voilà le constructeur :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    template<typename Type>
    Ptr_intelligent<Type>::Ptr_intelligent()
    {
    	allocateur<Type> alloc;
    	a = alloc;
    	ptr = a.allouer(1);
    	cpt_ref = new Compteur();
    	cpt_ref->incrementer();
    }
    et voilà le code dans l'allocateur :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    template<typename Type>
    Type * allocateur<Type>::allouer(size_t taille)
    {
    	Type* ptr;
    	ptr = (Type*) malloc(taille*sizeof(Type));
    	memoireAllouee= memoireAllouee+taille*sizeof(Type);
    	return ptr;
    }
    as tu une idée à ce niveau là ?
    Je pensais que a.allouer(1) allouerait 4 octets dans le tas et donc que je ne pourrais faire que *ptr ou ptr[0], mais certainement pas ptr[50] sans segfault.

    J'ai du mal à comprendre la situation

  4. #4
    Expert éminent sénior
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 630
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 630
    Points : 10 556
    Points
    10 556
    Par défaut
    Ton code est trop bancal

    • Un malloc au lieu d'un new.
    • ptr n'est pas désalloué
    • cpt_ref n'est pas désalloué
    • allocateur ne sert à rien? "Too much"?
    • memoireAllouee ne sert à rien et en plus il n'y a pas de relation entre la mémoire allouée et ce compteur (si tu alloues 2 blocs mais qu'un seul est désalloué il se passe quoi?)


    Tu sembles oublier que tu fais un sizeof : 1 * sizeof(int)

  5. #5
    Membre à l'essai
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2015
    Messages
    24
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 32
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mars 2015
    Messages : 24
    Points : 24
    Points
    24
    Par défaut
    Je n'ai pas copié le code en entier pour ne pas avoir plein de petits morceaux de code : ça serait trop long
    et le malloc n'était là que pour tester de toute façon

  6. #6
    Membre expert
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2011
    Messages
    739
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

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

    Informations forums :
    Inscription : Juin 2011
    Messages : 739
    Points : 3 627
    Points
    3 627
    Par défaut
    pourquoi je peux faire printf("%d %d \n",*p,p[50]); sans segfault ?
    Parce que personne ne vérifie que ptr[50] est alloué par ptr et que, manque de pot, ptr[50] est une zone mémoire accessible.
    Des outils d'analyse comme valgrind ou asan (-fsanitize-adress=address pour la plupart des compilateurs) vont probablement râler.


    Les lignes 5 et 6 concernant l'allocateur ne servent à rien. Dans le corps du constructeur, les variables membres sont déjà construites, donc a = alloc est totalement inutile. Si il y avait besoin de l'initialiser, c'est à faire dans la liste d'initialisation.
    Et il y a une fuite mémoire. Que se passe-t-il quand new Compteur envoi une exception ? Un peu de lecture http://www.stroustrup.com/except.pdf

    Concernant les allocateurs, leurs usages est généralement séparés en 2 parties: allocation de mémoire (allocate avec ::operator new) et construction de l'objet dans la zone alloué (construct avec [url=http://en.cppreference.com/w/cpp/language/new]placement new[/c]). Avec les fonctions inverses destruct et deallocate.

    Tu peux aussi allouer le compteur en même temps que Type (allocateur<struct{Compteur compteur, Type * p}).

  7. #7
    Membre à l'essai
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2015
    Messages
    24
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 32
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mars 2015
    Messages : 24
    Points : 24
    Points
    24
    Par défaut
    Oh punaise d'accord je commence à voir mes erreurs.

    Merci ! Je vais m'y remettre demain !

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

    Informations professionnelles :
    Activité : aucun

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

    Je ne vais pas revenir sur le reste, mais...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    allocateur<Type> alloc;  // (1)
    	a = alloc;  //(2)
    	ptr = a.allouer(1); // (3)
    ...

    Voyons si je comprend bien :
    En (1), tu crées un objet, nommé alloc, quo est de type allocateur<Type>... soit, cela semble cohérent avec l'idée généralement véhiculée par les pointeurs intelligents

    En (2), tu affecte à a (qui est une variable membre et qui a donc été créée automatiquement !!!) une copie de alloc... Et là, je commence à me poser de sérieuses questions :
    • L'allocateur créé par défaut étant tout à fait identique à celui que tu crée en déclarant alloc, y aurait-il une raison cachée à travailler en deux fois
    • Ne pourrais-tu pas, dans le pire des cas, écrire un code proche de a = allocateur<Type>{};
    • Et, tant qu'à faire, es tu vraiment obligé de garder une instance de ton allocateur tout au long de la durée de vie de tes instances


    Après tout, le besoin de l'allocateur est, théoriquement, limité à quelques fonctions bien particulières... Il pourrait être construit à chaque fois que tu veux faire une allocation et détruit dés que tu quitte la fonction dans laquelle cette allocation est effectuée, cela ne ralentirait pas les choses... Par contre, cela pourrait t'aider à "ménager" un tout petit peu la mémoire, en évitant d'utiliser inutilement quelques bytes
    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. #9
    Membre à l'essai
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2015
    Messages
    24
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 32
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mars 2015
    Messages : 24
    Points : 24
    Points
    24
    Par défaut
    Tu as tout à fait raison, mon code est plus ou moins rempli d'incohérence, je vais améliorer ça et le rendre plus propre,
    en soi je n'avais pas suffisamment compris le rôle de l'allocateur et surtout la place qu'a l'allocateur !

    Merci beaucoup en tout cas pour les remarques

  10. #10
    Membre expert
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2011
    Messages
    739
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

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

    Informations forums :
    Inscription : Juin 2011
    Messages : 739
    Points : 3 627
    Points
    3 627
    Par défaut
    Citation Envoyé par koala01 Voir le message
    • Et, tant qu'à faire, es tu vraiment obligé de garder une instance de ton allocateur tout au long de la durée de vie de tes instances


    Après tout, le besoin de l'allocateur est, théoriquement, limité à quelques fonctions bien particulières... Il pourrait être construit à chaque fois que tu veux faire une allocation et détruit dés que tu quitte la fonction dans laquelle cette allocation est effectuée, cela ne ralentirait pas les choses...
    Ce n'est pas une très bonne idée. Si l'allocateur à un état, tout fous le camp. Et si un allocateur ne peut pas avoir d'état, autant utiliser new/delete.
    D'ailleurs, les nouveaux allocateurs du standard ont des états.

    Une bonne implémentation de se type de pointeur devrait, amha, pouvoir prendre un allocateur en paramètre, allouer un segment de mémoire {T + Allocator} et déplacerait l'allocateur dans le segment alloué. Avec une optimisation comme EBO et si l'allocateur n'a pas d'état (cf: variable membre), il y a moyen d'avoir un segment mémoire de la taille d'un T. (petite article de présentation avec unique_ptr comme exemple).

Discussions similaires

  1. Surcharge de l'opérateur new
    Par :Bronsky: dans le forum C++
    Réponses: 17
    Dernier message: 27/10/2010, 21h33
  2. Compiler la surcharge de l'opérateur new
    Par mutagling dans le forum Langage
    Réponses: 1
    Dernier message: 24/06/2010, 07h24
  3. surcharger l'opérateur NEW
    Par spiner900 dans le forum Langage
    Réponses: 2
    Dernier message: 22/04/2010, 16h38
  4. Surcharge de l'opérateur new
    Par asoka13 dans le forum C++
    Réponses: 4
    Dernier message: 09/05/2008, 12h44
  5. namespace et opérateur new
    Par Sylvain Rousseau dans le forum C++
    Réponses: 3
    Dernier message: 06/01/2005, 23h24

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