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 :

subtilité des strings en C++


Sujet :

C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé
    Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Janvier 2004
    Messages
    58
    Détails du profil
    Informations personnelles :
    Localisation : Réunion

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

    Informations forums :
    Inscription : Janvier 2004
    Messages : 58
    Par défaut subtilité des strings en C++
    Bonjour, je viens du C et je dois avouer qu'a mon grand age, j'ai du mal à bien saisir les subtilités du C++.
    Je dois faire une toute petite modif d'une fonction:
    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
     
    bool BaseRTSPAppProtocolHandler::HandleRTSPResponse200Options(
                    RTSPProtocol *pFrom, Variant &requestHeaders, string &requestContent,
                    Variant &responseHeaders, string &responseContent) {
     
            if (pFrom->HasConnectivity()) {
                    //FINEST("This is a keep alive timer....");
                    return true;
            }    
     
            if (!pFrom->GetCustomParameters().HasKeyChain(V_STRING, true, 1, "connectionType")) {
                    FATAL("Bogus connection");
                    pFrom->EnqueueForDelete();
                    return false;
            }    
     
            //1. Sanitize
            if (!responseHeaders[RTSP_HEADERS].HasKey(RTSP_HEADERS_PUBLIC, false)) {
                    FATAL("Invalid response:\n%s", STR(responseHeaders.ToString()));
                    return false;
            }    
            //2. get the raw options
            string raw = responseHeaders[RTSP_HEADERS].GetValue(RTSP_HEADERS_PUBLIC,
                            false);
            }    
            printf("RAW HEADER: %s \n", STR(raw));
    }
    A la ligne 23 il semblerait qu'on crée un ojet string qui s'apelle raw, et on lui assigne une valeur qui vient d'une focntion.

    C'est parfait, je vois à peu près.

    Ce que je voudrais faire, c'est, en cas d'erreur, forcer la valeur de la string raw. Voici comment je m'y prends mal:
    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
    bool BaseRTSPAppProtocolHandler::HandleRTSPResponse200Options(
                    RTSPProtocol *pFrom, Variant &requestHeaders, string &requestContent,
                    Variant &responseHeaders, string &responseContent) {
            string raw; 
            if (pFrom->HasConnectivity()) {
                    //FINEST("This is a keep alive timer....");
                    return true;
            }    
    
            if (!pFrom->GetCustomParameters().HasKeyChain(V_STRING, true, 1, "connectionType")) {
                    FATAL("Bogus connection");
                    pFrom->EnqueueForDelete();
                    return false;
            }    
    
            //1. Sanitize
            if (!responseHeaders[RTSP_HEADERS].HasKey(RTSP_HEADERS_PUBLIC, false)) {
                    FATAL("Invalid response:\n%s", STR(responseHeaders.ToString()));
                    //return false;
                    //1.b if no Public field in the header, force the raw options
                    string raw = "DESCRIBE, PAUSE, PLAY, SETUP, TEARDOWN, OPTIONS, SET_PARAMETER";
            }    
            else {
                    //2. get the raw options
                    string raw = responseHeaders[RTSP_HEADERS].GetValue(RTSP_HEADERS_PUBLIC,
                            false);
            }    
            printf("RAW HEADER: %s \n", STR(raw));
    }
    Je crée mon string raw en ligne 5.
    Puis si la réponse n'est pas bonne, je la force en ligne 21, sinon, je fais comme avant en ligne 25.

    Ce qui ne marche pas, c'est que dans le premier cas, mon printf ligne 26 me renvoie bien la valeur reçue, mais dans le second ligne 28, il est toujours vide.

    Ce qui m'interpelle:
    C'est qu'en ligne 21 et 25, si je ne mets pas string devant raw, j'ai une erreur de compilation. Ce qui me laisse supposer que la variable raw n'est définie qu'entre les accolades, et que pour chaque bloc, j'ai un raw différent.
    l'erreur:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    note: candidates are:
    /usr/include/c++/4.6/bits/basic_string.h:541:7: note: std::basic_string<_CharT, _Traits, _Alloc>& std::basic_string<_CharT, _Traits, _Alloc>::operator=(const std::basic_string<_CharT, _Traits, _Alloc>&) [with _CharT = char, _Traits = std::char_traits<char>, _Alloc = std::allocator<char>, std::basic_string<_CharT, _Traits, _Alloc> = std::basic_string<char>]
    /usr/include/c++/4.6/bits/basic_string.h:549:7: note: std::basic_string<_CharT, _Traits, _Alloc>& std::basic_string<_CharT, _Traits, _Alloc>::operator=(const _CharT*) [with _CharT = char, _Traits = std::char_traits<char>, _Alloc = std::allocator<char>, std::basic_string<_CharT, _Traits, _Alloc> = std::basic_string<char>] <near match>
    Si une Grande âme pouvait m'expliquer comment me dépatouiller de ça, ce serait le premier rayon de soleil de ma pauvre semaine.

  2. #2
    Membre confirmé
    Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Janvier 2004
    Messages
    58
    Détails du profil
    Informations personnelles :
    Localisation : Réunion

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

    Informations forums :
    Inscription : Janvier 2004
    Messages : 58
    Par défaut
    C'est bon, j'ai trouvé, il suffisait de comprendre les insultes du compilo...
    En fait il faut bien déclarer l'objet string en tête de fonction, mais lorsque je dois attribuer une valeur qui vient d'une autre fonction, je dois 'caster' le retour afin que le compilo sache quelle string il doit untiliser.

    Voici donc le code corrigé:
    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
     
    bool BaseRTSPAppProtocolHandler::HandleRTSPResponse200Options(
                    RTSPProtocol *pFrom, Variant &requestHeaders, string &requestContent,
                    Variant &responseHeaders, string &responseContent) {
            string raw; 
            if (pFrom->HasConnectivity()) {
                    //FINEST("This is a keep alive timer....");
                    return true;
            }    
     
            if (!pFrom->GetCustomParameters().HasKeyChain(V_STRING, true, 1, "connectionType")) {
                    FATAL("Bogus connection");
                    pFrom->EnqueueForDelete();
                    return false;
            }    
     
            //1. Sanitize
            if (!responseHeaders[RTSP_HEADERS].HasKey(RTSP_HEADERS_PUBLIC, false)) {
                    WARN("Invalid response:\n%s", STR(responseHeaders.ToString()));
                    //1.b if no Public field in the header, force the raw options
                    raw = "DESCRIBE, PAUSE, PLAY, SETUP, TEARDOWN, OPTIONS, SET_PARAMETER";
            }    
            else {
                    //2. get the raw options
                    raw = STR(responseHeaders[RTSP_HEADERS].GetValue(RTSP_HEADERS_PUBLIC,
                            false));
            }    
            printf("RAW HEADER: %s \n", STR(raw));
    }
    avec la macro qui va bien:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    #define STR(x) (((string)(x)).c_str())
    JE ne comprends pas vraiment pourquoi lorsque je crée l'objet, je n'ia pas besoin de 'caster' mais je comprends que je ne pourrai jamais tout comprendre..

    Si quelqu'un veut ajouter une explication, elle sera la bienvenue

  3. #3
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Salut,

    En fait, il faudrait voir ce que renvoie la fonction GetValue() de ta variable responseHeaders[RTSP_HEADERS].

    Si c'est une chaine de caractères C style (un const char * "classique", terminé par '\0'), tu n'as pas besoin de caster le résultat renvoyé par la fonction, l'opérateur d'affectation de std::string s'occupera de faire le travail.

    Si c'est "autre chose", il faudra sans doute veiller à faire "mieux" qu'un cast "brutal", mais envisager une conversion "cohérente"

    Par contre, c'est au niveau de printf qu'il peut y avoir un problème, car printf ne sait pas utiliser un objet de type std::string (cette fonction ne peut utiliser que des types primitifs comme argument > 1).

    Le type qui se rapproche le plus std:string que printf peut utiliser, c'est la chaine de caractères C-style.

    Il n'est pas nécessaire de caster la std::string en const char * pour l'utiliser avec printf, mais il suffit d'utiliser la fonction c_str() qui renvoie, justement, une chaine de caractères C-style
    un code proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    void foo(){
        std::string raw;
        /* ... */
        raw = responseHeaders[RTSP_HEADERS].GetValue(RTSP_HEADERS_PUBLIC,
                            false); /* GetValue renvoie un const char * */
       printf("blabla %s",raw.c_str());
    }
    est donc parfaitement valide et fonctionne sans problème

    Ceci dit, le problème venait essentiellement de la portée des variables.

    Les variables n'existent qu'entre le moment de leur déclaration et dans la portée dans laquelle elles sont déclarées. Et les variable peuvent jouer à cache cache dans les différentes portées:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    void foo(){
        std::string raw("hello");
        {
            std::string raw("world"); // cache la première variable raw
            printf("%s",raw.c_str()); // affiche "world"
        }
        printf("%s",raw.c_str()); // affiche "hello"
    }
    C'est le problème auquel tu étais confronté avec tes lignes 4, 21 et 25 et que tu constatais en ligne 28 : à la ligne 4 tu créais une première variable nommée raw, aux lignes 21 et 28, tu créais une variable raw qui, dans la portée dans laquelle elle était déclarée, cachait celle qui était déclarée en ligne 4 et, en ligne 28, tu te retrouvais avec la seule variable raw qui existe encore à ce moment là (parce que tu es sorti des deux if), à savoir : celle qui avait été déclarée en ligne 4.

    La correction était donc beaucoup plus simple que ce que tu n'a fait : il "suffit" d'affecter les différentes valeurs à raw, sans déclarer une nouvelle variable (mais en utilisant celle qui est déclarée en ligne 4).

    ... Et, bien sur, d'utiliser la fonction c_str() de raw afin de pouvoir transmettre un const char * à printf en ligne 28 :
    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
    bool BaseRTSPAppProtocolHandler::HandleRTSPResponse200Options(
                    RTSPProtocol *pFrom, Variant &requestHeaders, string &requestContent,
                    Variant &responseHeaders, string &responseContent) {
            string raw; 
            if (pFrom->HasConnectivity()) {
                    //FINEST("This is a keep alive timer....");
                    return true;
            }    
     
            if (!pFrom->GetCustomParameters().HasKeyChain(V_STRING, true, 1, "connectionType")) {
                    FATAL("Bogus connection");
                    pFrom->EnqueueForDelete();
                    return false;
            }    
     
            //1. Sanitize
            if (!responseHeaders[RTSP_HEADERS].HasKey(RTSP_HEADERS_PUBLIC, false)) {
                    FATAL("Invalid response:\n%s", STR(responseHeaders.ToString()));
                    //return false;
                    //1.b if no Public field in the header, force the raw options
                    /* pas string raw, mais juste raw */
                    raw = "DESCRIBE, PAUSE, PLAY, SETUP, TEARDOWN, OPTIONS, SET_PARAMETER";
            }    
            else {
                    //2. get the raw options
                    /* pas string raw, mais juste raw */
                    raw = responseHeaders[RTSP_HEADERS].GetValue(RTSP_HEADERS_PUBLIC,
                            false);
            }    
            /* utiliser c_str() pour avoir un const char * */
            printf("RAW HEADER: %s \n", raw.c_str());
    }
    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

  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
    Bonjour,
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    raw = STR(responseHeaders[RTSP_HEADERS].GetValue(RTSP_HEADERS_PUBLIC,
                            false));
    Si ce cast fonctionne réellement c'est probablement grâce à un énorme coup de bol.

    Une std::string est souvent implémenté sous la forme :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    struct std::string
    {
       char* m_str;
       int   m_size;
       int m_capacity;
       // ...
    }
     
    std::string::c_str
    {
       return m_str;
    }

    Donc je suppose que le machin renvoyé par GetValue() est une sorte de structure qui commence elle aussi par un char* donc par chance le cast fonctionne.

    C'est dommage que tu nous ais montré que la fin de l'erreur, normalement on devrait avoir une erreur du style :

    Impossible d'utiliser std::string::operator= avec le type "qqchose"

    car les seul candidats pour l'operator= disponibles sont

    operator=(const std::string&)
    operator=(char*)
    On aurait pu voir le tyep renvoyé par GetValue...

  5. #5
    Membre Expert
    Homme Profil pro
    Inscrit en
    Décembre 2010
    Messages
    734
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Décembre 2010
    Messages : 734
    Par défaut
    Citation Envoyé par Arzar Voir le message
    On aurait pu voir le tyep renvoyé par GetValue...
    Au hasard, une variante de char* ?

  6. #6
    Membre confirmé
    Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Janvier 2004
    Messages
    58
    Détails du profil
    Informations personnelles :
    Localisation : Réunion

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

    Informations forums :
    Inscription : Janvier 2004
    Messages : 58
    Par défaut
    Wahou,

    Merci a tous pour vos réponses, je vois le C++ sous un jour nouveau.

    En ce qui concerne la portée des variables, j'étais bien conscient en le faisant que ça n'avait rien de logique, mais dans le désespoir, on tente tout

    Tout dépend donc de ce que renvoie GetValue()
    Voici donc la fonction GetValue:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
     Variant &Variant::GetValue(string key, bool caseSensitive) {
      if (caseSensitive) {
      return (*this)[key];
      } else {
     
      FOR_MAP(*this, string, Variant, i) {
      if (lowerCase(MAP_KEY(i)) == lowerCase(key))
      return MAP_VAL(i);
      }
     
      return (*this)[key];
      }
     }
    elle renvoie donc un variant, je suppose que ça n'aide pas, En cherchant un peu, je vois une classe variant qui peut être surchargée.

    Si on lui passe un string, voici ce que ça donne:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     Variant::Variant(const string &val) {
      CONSTRUCTOR;
      _type = V_STRING;
      memset(&_value, 0, sizeof (_value));
      DYNAMIC_ALLOC("_value.s");
      _value.s = new string(val);
     }
    Donc d'après ce que je comprends, GetValue() renvoie un string.

    Ce qui veut dire que vous avez raison:
    Il n'est pas nécessaire de caster la std::string en const char * pour l'utiliser avec printf, mais il suffit d'utiliser la fonction c_str() qui renvoie, justement, une chaine de caractères C-style
    un code proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    void foo(){
        std::string raw;
        /* ... */
        raw = responseHeaders[RTSP_HEADERS].GetValue(RTSP_HEADERS_PUBLIC,
                            false); /* GetValue renvoie un const char * */
       printf("blabla %s",raw.c_str());
    }
    est donc parfaitement valide et fonctionne sans problème
    je ne devrais pas avoir à 'caster'.
    Ceci dit, comme vous pouvez le constater, j'ai mis caster entre guillemets, car je ne fais pas un cast, mais j'utilise une macro:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    #define STR(x) (((string)(x)).c_str())
    qui utilise bien la fonction c_str(), donc pour le printf, tout va bien.

    Ce que je ne comprends pas, c'est que si je n'utilise pas cette macro pour récupérer le retour de GetValue(), le compilo me renvoie une erreur.
    si je compile ça:
    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
    bool BaseRTSPAppProtocolHandler::HandleRTSPResponse200Options(
                    RTSPProtocol *pFrom, Variant &requestHeaders, string &requestCon
                    Variant &responseHeaders, string &responseContent) {
            string raw;
     
            //1. Sanitize
            if (!responseHeaders[RTSP_HEADERS].HasKey(RTSP_HEADERS_PUBLIC, false)) {
                    WARN("Invalid response:\n%s", STR(responseHeaders.ToString()));
            //      return false;
                    //1.b if no Public field in the header, force the raw options
                    raw = "DESCRIBE, PAUSE, PLAY, SETUP, TEARDOWN, OPTIONS,  SET_PARAMETER";
            }
            else {
                    //2. get the raw options
                    raw = responseHeaders[RTSP_HEADERS].GetValue(RTSP_HEADERS_PUBLIC
                            false);
            }
            printf("RAW STRING: %s", STR(raw));
    }
    voici l'insulte du compilo:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    /src/protocols/rtp/basertspappprotocolhandler.cpp: In member function âvirtual bool BaseRTSPAppProtocolHandler::HandleRTSPResponse200Options(RTSPProtocol*, Variant&, std::string&, Variant&, std::string&)â:
    /src/protocols/rtp/basertspappprotocolhandler.cpp:985:9: error: ambiguous overload for âoperator=â in âraw = (&(& responseHeaders)->Variant::operator[](((const char*)"headers")))->Variant::GetValue(std::basic_string<char>(((const char*)"Public"), (*(const std::allocator<char>*)(& std::allocator<char>()))), 0)â
    /src/protocols/rtp/basertspappprotocolhandler.cpp:985:9: note: candidates are:
    /usr/include/c++/4.6/bits/basic_string.h:541:7: note: std::basic_string<_CharT, _Traits, _Alloc>& std::basic_string<_CharT, _Traits, _Alloc>::operator=(const std::basic_string<_CharT, _Traits, _Alloc>&) [with _CharT = char, _Traits = std::char_traits<char>, _Alloc = std::allocator<char>, std::basic_string<_CharT, _Traits, _Alloc> = std::basic_string<char>]
    /usr/include/c++/4.6/bits/basic_string.h:549:7: note: std::basic_string<_CharT, _Traits, _Alloc>& std::basic_string<_CharT, _Traits, _Alloc>::operator=(const _CharT*) [with _CharT = char, _Traits = std::char_traits<char>, _Alloc = std::allocator<char>, std::basic_string<_CharT, _Traits, _Alloc> = std::basic_string<char>] <near match>
    /usr/include/c++/4.6/bits/basic_string.h:549:7: note:   no known conversion for argument 1 from âVariantâ to âconst char*â
    /usr/include/c++/4.6/bits/basic_string.h:560:7: note: std::basic_string<_CharT, _Traits, _Alloc>& std::basic_string<_CharT, _Traits, _Alloc>::operator=(_CharT) [with _CharT = char, _Traits = std::char_traits<char>, _Alloc = std::allocator<char>, std::basic_string<_CharT, _Traits, _Alloc> = std::basic_string<char>]
    make[2]: *** [/src/protocols/rtp/basertspappprotocolhandler.cpp.o] Error 1
    make[1]: *** [thelib/CMakeFiles/thelib.dir/all] Error 2
    make: *** [all] Error 2
    La ligne 985 de mon code étant celle de la ligne 16 citée ici.

    Donc l'erreur du compilo me dit bien que l'erreur vient du retour de GetValue() qui renvoie un variant, or le compilo ne sait comment ranger ça dans une string.

    J'ai un peu de mal avec ces histoires de surcharges de fonctions, et je dois avouer que je ne comprends toujours pas pourquoi je dois utiliser c_str() pour renvoyer ma valeur dans le raw si je le déclare en début de fonction alors que la déclaration à la volée:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    string raw = responseHeaders[RTSP_HEADERS].GetValue(RTSP_HEADERS_PUBLIC,
                            false);
    passe très bien sans utiliser la focntion c_str() de ma macro.


    Si vous voulez plus d'infos sur ce qu'est un variant, voici l'ensemble des possibilités:
    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
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    5 Variant::Variant() {
      CONSTRUCTOR;
      _type = V_NULL;
      memset(&_value, 0, sizeof (_value));
     }
     
     Variant::Variant(const Variant &val) {
      CONSTRUCTOR;
      InternalCopy(val);
     }
     
     Variant::Variant(const bool &val) {
      CONSTRUCTOR;
      _type = V_BOOL;
      memset(&_value, 0, sizeof (_value));
      _value.b = val;
     }
     
     Variant::Variant(const int8_t &val) {
      CONSTRUCTOR;
      _type = V_INT8;
      memset(&_value, 0, sizeof (_value));
      _value.i8 = val;
     }
     
     Variant::Variant(const int16_t &val) {
      CONSTRUCTOR;
      _type = V_INT16;
      memset(&_value, 0, sizeof (_value));
      _value.i16 = val;
     }
     
     Variant::Variant(const int32_t &val) {
      CONSTRUCTOR;
      _type = V_INT32;
      memset(&_value, 0, sizeof (_value));
      _value.i32 = val;
     }
     
     Variant::Variant(const int64_t &val) {
      CONSTRUCTOR;
      _type = V_INT64;
      memset(&_value, 0, sizeof (_value));
      _value.i64 = val;
     }
     
     Variant::Variant(const uint8_t &val) {
      CONSTRUCTOR;
      _type = V_UINT8;
      memset(&_value, 0, sizeof (_value));
      _value.ui8 = val;
     }
     
     Variant::Variant(const uint16_t &val) {
      CONSTRUCTOR;
      _type = V_UINT16;
      memset(&_value, 0, sizeof (_value));
      _value.ui16 = val;
     }
     
     Variant::Variant(const uint32_t &val) {
      CONSTRUCTOR;
      _type = V_UINT32;
      memset(&_value, 0, sizeof (_value));
      _value.ui32 = val;
     }
     
     Variant::Variant(const uint64_t &val) {
      CONSTRUCTOR;
      _type = V_UINT64;
      memset(&_value, 0, sizeof (_value));
      _value.ui64 = val;
     }
     
     Variant::Variant(const double &val) {
      CONSTRUCTOR;
      _type = V_DOUBLE;
      memset(&_value, 0, sizeof (_value));
      _value.d = val;
     }
     
     Variant::Variant(const Timestamp &val) {
      CONSTRUCTOR;
      _type = V_TIMESTAMP;
      memset(&_value, 0, sizeof (_value));
      DYNAMIC_ALLOC("_value.t");
      _value.t = new Timestamp;
      *_value.t = val;
      NormalizeTs();
     }
     
     Variant::Variant(const uint16_t year, const uint8_t month, const uint8_t day) {
      CONSTRUCTOR;
      _type = V_DATE;
      memset(&_value, 0, sizeof (_value));
      DYNAMIC_ALLOC("_value.t");
      _value.t = new Timestamp;
      memset(_value.t, 0, sizeof (Timestamp));
      _value.t->tm_year = year - 1900;
      _value.t->tm_mon = month - 1;
      _value.t->tm_mday = day;
      _value.t->tm_hour = 0;
      _value.t->tm_min = 0;
      _value.t->tm_sec = 0;
      NormalizeTs();
     }
     
     Variant::Variant(const uint8_t hour, const uint8_t min, const uint8_t sec, const uint16_t m) {
      CONSTRUCTOR;
      _type = V_TIME;
      memset(&_value, 0, sizeof (_value));
      DYNAMIC_ALLOC("_value.t");
      _value.t = new Timestamp;
      memset(_value.t, 0, sizeof (Timestamp));
      _value.t->tm_year = 70;
      _value.t->tm_mon = 0;
      _value.t->tm_mday = 1;
      _value.t->tm_hour = hour;
      _value.t->tm_min = min;
      _value.t->tm_sec = sec;
      NormalizeTs();
     }
     
     Variant::Variant(const uint16_t year, const uint8_t month, const uint8_t day,
      const uint8_t hour, const uint8_t min, const uint8_t sec, const uint16_t m) {
      CONSTRUCTOR;
      _type = V_TIMESTAMP;
      memset(&_value, 0, sizeof (_value));
      DYNAMIC_ALLOC("_value.t");
      _value.t = new Timestamp;
      memset(_value.t, 0, sizeof (Timestamp));
      _value.t->tm_year = year - 1900;
      _value.t->tm_mon = month - 1;
      _value.t->tm_mday = day;
      _value.t->tm_hour = hour;
      _value.t->tm_min = min;
      _value.t->tm_sec = sec;
      NormalizeTs();
     }
     
     Variant::Variant(const char *pVal) {
      CONSTRUCTOR;
      _type = V_STRING;
      memset(&_value, 0, sizeof (_value));
      DYNAMIC_ALLOC("_value.s");
      _value.s = new string(pVal);
     }
     
     Variant::Variant(const string &val) {
      CONSTRUCTOR;
      _type = V_STRING;
      memset(&_value, 0, sizeof (_value));
      DYNAMIC_ALLOC("_value.s");
      _value.s = new string(val);
     }
     
     Variant::~Variant() {
      DESTRUCTOR;
      Reset();
     }
    Dans tous les cas, un tout grand merci à vous pour vos précieuses informations

  7. #7
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Citation Envoyé par gigiskhan Voir le message
    Wahou,

    Merci a tous pour vos réponses, je vois le C++ sous un jour nouveau.

    En ce qui concerne la portée des variables, j'étais bien conscient en le faisant que ça n'avait rien de logique, mais dans le désespoir, on tente tout

    Tout dépend donc de ce que renvoie GetValue()
    Voici donc la fonction GetValue:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
     Variant &Variant::GetValue(string key, bool caseSensitive) {
      if (caseSensitive) {
      return (*this)[key];
      } else {
     
      FOR_MAP(*this, string, Variant, i) {
      if (lowerCase(MAP_KEY(i)) == lowerCase(key))
      return MAP_VAL(i);
      }
     
      return (*this)[key];
      }
     }
    elle renvoie donc un variant, je suppose que ça n'aide pas, En cherchant un peu, je vois une classe variant qui peut être surchargée.

    Si on lui passe un string, voici ce que ça donne:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     Variant::Variant(const string &val) {
      CONSTRUCTOR;
      _type = V_STRING;
      memset(&_value, 0, sizeof (_value));
      DYNAMIC_ALLOC("_value.s");
      _value.s = new string(val);
     }
    Donc d'après ce que je comprends, GetValue() renvoie un string.
    Ah, ben non!

    GetValue renvoie un objet de type ... Variant.

    La notion la plus proche de Variant que tu aies en C est le void *, avec un le type ereasure et l'approche orientée objet en moins : Cela peut représenter strictement tout et n'importe quoi.

    alors, bien sur, cela peut entre autres représenter une chaîne de caractères, mais cela peut tout aussi bien représenter un int qu'un double ou même la lune

    Par contre, tu devrais voir du coté de la classe Variant en question... Elle devrait te fournir une fonction (toString(), peut être) qui te permettra de récupérer l'information en étant sûr qu'elle est sous la forme d'une chaine de caractères
    Ceci dit, comme vous pouvez le constater, j'ai mis caster entre guillemets, car je ne fais pas un cast, mais j'utilise une macro:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    #define STR(x) (((string)(x)).c_str())
    qui utilise bien la fonction c_str(), donc pour le printf, tout va bien.
    Heuu... Excuses moi, mais moi, ce que je lis de la macro, c'est surtout (string)(x)!!! Et ca, c'est un transtypage C-style, même s'il est caché par la macro

    Ce que je ne comprends pas, c'est que si je n'utilise pas cette macro pour récupérer le retour de GetValue(), le compilo me renvoie une erreur.
    si je compile ça:
    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
    bool BaseRTSPAppProtocolHandler::HandleRTSPResponse200Options(
                    RTSPProtocol *pFrom, Variant &requestHeaders, string &requestCon
                    Variant &responseHeaders, string &responseContent) {
            string raw;
     
            //1. Sanitize
            if (!responseHeaders[RTSP_HEADERS].HasKey(RTSP_HEADERS_PUBLIC, false)) {
                    WARN("Invalid response:\n%s", STR(responseHeaders.ToString()));
            //      return false;
                    //1.b if no Public field in the header, force the raw options
                    raw = "DESCRIBE, PAUSE, PLAY, SETUP, TEARDOWN, OPTIONS,  SET_PARAMETER";
            }
            else {
                    //2. get the raw options
                    raw = responseHeaders[RTSP_HEADERS].GetValue(RTSP_HEADERS_PUBLIC
                            false);
            }
            printf("RAW STRING: %s", STR(raw));
    }
    L'erreur sans la macro vient, justement, du fait que GetValue renvoie un objet de type Variant, qui n'a strictement rien à voir avec une string ni avec n'importe quel autre type que... Variant lui-même.

    Le fait que cela passe avec la macro vient, quant à lui, du fameux (string)(x) qui occasionne un cast c_style en string.

    Le problème, c'est que ta macro te fait mentir au compilateur en lui disant (je schématise ) "Tu peux me croire sur parole, ce que je te transmet est bel et bien une chaine de caractères".

    Sauf que... Si ca peut effectivement être une chaine de caractères, cela peut tout aussi bien être tout et n'importe quoi d'autre

    Ta macro arme donc un six coup avec 5 balles et fait tourner le barillet! :

    Si la valeur représentée par le Variant est bien une chaine de caractères, ca passera. Mais si la valeur est un entier (ou un float ou n'importe quel type primitif), tu risques déjà d'avoir quelques surprises.

    Et si la valeur représentée par le Variant est une classe (surtout si elle a sémantique d'entité)... Ah!!! bobo!!!
    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

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

Discussions similaires

  1. Recupérer des string
    Par frozon dans le forum Langage
    Réponses: 5
    Dernier message: 09/01/2006, 10h28
  2. DLL : récupérer des string/PChar...
    Par the_magik_mushroom dans le forum Langage
    Réponses: 8
    Dernier message: 10/11/2005, 10h58
  3. Mauvais tri des String avec des accents
    Par lbreuillard dans le forum Collection et Stream
    Réponses: 2
    Dernier message: 23/09/2005, 12h21
  4. [débutant]modifier des string
    Par calavera dans le forum SL & STL
    Réponses: 1
    Dernier message: 16/09/2005, 20h45
  5. problème our passer des string dans tableau d'int
    Par Battosaiii dans le forum C++
    Réponses: 9
    Dernier message: 15/07/2004, 17h42

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