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 :

Retourner un pointeur sur un objet statique interne � une fonction ?


Sujet :

C++

  1. #1
    Membre Expert

    Inscrit en
    Mai 2008
    Messages
    1 014
    D�tails du profil
    Informations forums :
    Inscription : Mai 2008
    Messages : 1 014
    Par d�faut Retourner un pointeur sur un objet statique interne � une fonction ?
    Bonjour � tous !

    Je viens de tomber sur ce bout de code dans une librairie tierce que j'utilise :

    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    template<class T>
    char const *
    ConvertToString( T const & t )
    {
      std::stringstream str;
      static std::string strOut;
      str << t;
      strOut = str.str();
      return strOut.c_str();
    }
    A votre avis, est-ce que ce genre de code (renvoi d'un pointeur sur un objet statique) est correct, robuste et sans vice cach� ?

  2. #2
    R�dacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    D�tails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Par d�faut
    Y a pas mal de biblioth�ques qui font �a. La seule chose c'est que chaque nouvel appel invalide l'adresse pr�c�demment renvoy�e. Donc, tu ne peux pas la garder pour un usage ult�rieur.
    Donc :
    -> correct : il me semble que oui
    -> robuste : non
    -> vices cach�s : la personne qui arrive apr�s toi et qui n'a pas la curiosit� de regarder l'impl�mentation et pense pouvoir garder le pointeur d'une fois sur l'autre

  3. #3
    Membre Expert
    Avatar de Goten
    Profil pro
    Inscrit en
    Juillet 2008
    Messages
    1 580
    D�tails du profil
    Informations personnelles :
    �ge : 35
    Localisation : France

    Informations forums :
    Inscription : Juillet 2008
    Messages : 1 580
    Par d�faut
    Quel est l'int�r�t au final? L� j'avoue que je vois mal comment quelqu'un a pu se dire :
    "tiens et si je renvoyais un pointeur sur une donn�e statique interne � une fonction?"

  4. #4
    Membre Expert

    Inscrit en
    Mai 2008
    Messages
    1 014
    D�tails du profil
    Informations forums :
    Inscription : Mai 2008
    Messages : 1 014
    Par d�faut
    Merci !

    Citation Envoy� par 3DArchi
    -> correct : il me semble que oui
    -> robuste : non
    -> vices cach�s : la personne qui arrive apr�s toi et qui n'a pas la curiosit� de regarder l'impl�mentation et pense pouvoir garder le pointeur d'une fois sur l'autre
    Ok, j'en �tais arriv� � peu pr�s aux m�mes conclusions, merci pour la confirmation.

    Quel est l'int�r�t au final? L� j'avoue que je vois mal comment quelqu'un a pu se dire :
    "tiens et si je renvoyais un pointeur sur une donn�e statique interne � une fonction?"
    Alors, j'ai inspect� un peu plus le code de la biblioth�que. En fait, je suspecte que son auteur pensait avoir trouv� une superbe feinte pour �conomiser des copies, mais qu'il a oubli� dans son analyse la RVO/NRVO.

    Il n'utilise la fonction ConvertToString que de deux mani�res :
    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    // 1ere manière
    std::string s = ConvertToString(data);
     
    // 2eme manière
    Truc truc( ConvertToString( data ) );
     
    // avec
    Truc::Truc(const std::string& value):value_(value){}
    Donc il n'a pas de probl�me de dur�e de vie du pointeur car il copie syst�matiquement le retour de ConvertToString dans une std::string. Mais au final, il fait une copie de plus que le code de la faq :
    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    template<typename T>
    std::string to_string( const T & Value )
    {
        // utiliser un flux de sortie pour créer la chaîne
        std::ostringstream oss;
        // écrire la valeur dans le flux
        oss << Value;
        // renvoyer une string
        return oss.str(); // RVO possible ici.
    }
    qui exploite la RVO.

    (Enfin, si je ne me suis pas plant� en testant. Pour r�f�rence, je laisse ci-dessous mon code de test)
    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
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
     
    #include <iostream>
    #include <string>
     
    struct A
    {
        A(){std::cout << "default ctor" << std::endl;}
        A(A* a){std::cout << "ctor A*" << std::endl;}
        A(const A& a){std::cout << "copy ctor" << std::endl;}
        A& operator=(const A& x){std::cout << "copy op=" << std::endl; return *this;}
        ~A(){std::cout << "dtor" << std::endl;}
    };
     
    struct B
    {
        B(const A& a):a_(a){}
        B(A* a):a_(a){}
     
        A a_;
    };
     
    // fake stringstream
    struct stringstream
    {
        A str()
        {
            A a;
            // do something...
            return a;
        }
    };
     
    template<class T>
    A* ConvertToAPtr( T const & t )
    {
        static A strOut;
        stringstream str;
        // str << t;
        strOut = str.str();
        return &strOut;
    }
     
    template<class T>
    A ConvertToA( T const & t )
    {
        stringstream str;
        //str << t
        return str.str();
    }
     
     
    int main()
    {
        std::cout << "ConvertToAPtr(T); (Warm up static data)\n";
        ConvertToAPtr(16);
     
        std::cout << "\nA a(ConvertToAPtr(T)\n";
        A a1(ConvertToAPtr(16));
     
        printf("\nB b(ConvertToAPtr(T)\n"); 
        B b1(ConvertToAPtr(15));
     
        printf("\nA a(ConvertToA(T)); (Note : NRVO here)\n");
        A a2(ConvertToA(16));
     
        std::cout << "\nB b(ConvertToA(T));\n";
        B b2(ConvertToA(15));
     
        printf("\nEND\n");
     
        return 0;
    }

  5. #5
    R�dacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    D�tails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Par d�faut
    Citation Envoy� par Arzar Voir le message
    Alors, j'ai inspect� un peu plus le code de la biblioth�que. En fait, je suspecte que son auteur pensait avoir trouv� une superbe feinte pour �conomiser des copies, mais qu'il a oubli� dans son analyse la RVO/NRVO.
    C'est une technique que j'ai vu beaucoup employ�e dans du code C embarqu�. Quelque chose du genre :
    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
    4
    5
    6
    7
     
    char const *do_something(/*...*/)
    {
      static char result[TAILLE];
       /*...*/
      return result;
    }
    La zone m�moire est de taille fixe, il n'y a pas d'�chec d'allocation possible et on connait l'occupation m�moire d�s la compilation (et si c'est une variable globale, je crois qu'on peut m�me choisir son emplacement).
    Ca peut donc �tre aussi quelqu'un qui a repris ses habitudes C en les appliquant � un code C++ o� cela devient caduc voire, comme tu dis, p�nalisant (car dans ton exemple il y aura allocation et recopie et on perd le b�n�fice de la (N)RVO) .

  6. #6
    Expert �minent
    Avatar de M�dinoc
    Homme Profil pro
    D�veloppeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 397
    D�tails du profil
    Informations personnelles :
    Sexe : Homme
    �ge : 41
    Localisation : France

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 397
    Par d�faut
    En plus, ce n'est �videmment pas r�entrant, et plus grave, avec une impl�mentation aussi "na�ve", ce n'est pas thread-safe (il faudrait utiliser explicitement ou implicitement du Thread-Local Storage).
    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.

  7. #7
    Membre chevronn�

    Inscrit en
    Ao�t 2007
    Messages
    300
    D�tails du profil
    Informations forums :
    Inscription : Ao�t 2007
    Messages : 300
    Par d�faut
    Le renvoi d'un pointeur sur un objet statique renvoie bien la m�me chose d'une fois sur l'autre, mais dans le code pr�sent�, ce qui est renvoy� n'est pas un "pointeur sur un objet statique interne � une fonction", mais le r�sultat d'une requ�te sur un objet (qui en l'occurrence est statique � une fonction, mais le probl�me ne vient pas de l�).

    Le r�sultat de cette requ�te peut �tre invalid�, comme pour bien des objets; c'est un peu comme si on renvoyait un vector<T>::begin(): cela n'est ni bon ni mauvais en soi, il faut simplement tenir compte de la dur�e de vie du pointeur en question. En l'occurrence, la valeur de retour deviendra fausse d�s l'appel suivant, non pas parce que l'objet en question �tait local � une fonction, non pas parce que la proc�dure n'est pas thread-safe, mais tout simplement parce que le contenu de l'objet change, et donc que la r�sultat de la requ�te pr�c�dente devient invalide. En gros, ce code est exactement aussi faux que:

    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
    4
    5
    vector<int>  a;
        a.push_back(5);
    vector<int>::const_iterator pa = a.begin();
        a.clear();
        cout << *pa;
    Le code pr�sent� est mauvais sans aucun doute, mais d'abord pour des raisons de parall�lisme, et non pas pour des raisons de dur�e de vie du r�sultat: il est difficile de croire qu'un utilisateur d�duirait de la signature de la fonction ("char const *ConvertToString( T const & t )") que le pointeur retourn� a une dur�e de vie d�passant la s�quence d'appel.

    Il me semble donc qu'il y a dans les commentaires quelques confusions quant aux causes du probl�me: la non-r�entrance est effectivement due � l'utilisation d'une variable statique interne � la fonction, ce qui correspond au titre de la discussion. Par contre, la non-conservation de la valeur n'est pas supposable d'apr�s la signature, n'est pas due au fait que l'objet est statique et interne � la fonction, et est donc sans rapport avec le titre de la discussion.

Discussions similaires

  1. Savoir sur quel objet s'applique une fonction
    Par Kazuko dans le forum G�n�ral JavaScript
    R�ponses: 6
    Dernier message: 16/11/2011, 16h36
  2. utilisations de pointeurs sur des objets
    Par niarkyzator dans le forum Delphi
    R�ponses: 21
    Dernier message: 13/12/2006, 09h42
  3. R�ponses: 1
    Dernier message: 14/11/2004, 14h26
  4. vector de pointeurs sur des objet
    Par jean-bobby dans le forum SL & STL
    R�ponses: 26
    Dernier message: 06/08/2004, 14h54
  5. Declaration de fonction retournant un pointeur sur fonction
    Par pseudokifaitladiff�rence dans le forum C
    R�ponses: 5
    Dernier message: 11/08/2003, 19h37

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