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 :

Assignation d'une variable avec la valeur de retour d'une méthode de classe (VC11)


Sujet :

C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre à l'essai
    Inscrit en
    Août 2006
    Messages
    4
    Détails du profil
    Informations forums :
    Inscription : Août 2006
    Messages : 4
    Par défaut Assignation d'une variable avec la valeur de retour d'une méthode de classe (VC11)
    Voici ma problématique. J'ai une classe client qui ressemble à ceci :
    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
     
    #include <string>
     
    using namespace std;
     
    class client
    {
    	string _firstname;
    	string _lastname;
    public:
    	client();
    	client(string,string);
    	~client();
    	string firstname();
    	string lastname();
    };
    Et voici ce que fait la méthode qui retourne _firstname (c'est tout con) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    string client::firstname()
    {
    	return _firstname;
    }
    Mon souci vient du fait que je souhaite utiliser sqlite et une des méthodes (pour lier des paramètres à la requête) a cette signature :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    // le 3ième paramètre, const char*, est la valeur que je souhaite passer
    SQLITE_API int SQLITE_STDCALL sqlite3_bind_text(sqlite3_stmt*,int,const char*,int,void(*)(void*));
    Dans ma grande naïveté, j'ai pensé qu'en exécutant le code suivant tout était bon (c_str() retourne un const char* vers le contenu de ma string):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    sqlite3_bind_text(stmt, 1, client.firstname().c_str(), client.firstname().size(), SQLITE_STATIC);
    Mais aucune valeur n'est inscrite dans la BD.
    Si je fais l'opération suivante, tout fonctionne :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    string buf = client.firstname();
    sqlite3_bind_text(stmt, 1, buf.c_str(), client.firstname().size(), SQLITE_STATIC);
    Quelqu'un peut m'expliquer pourquoi je ne peux pas utiliser c_str() directement sur la valeur retournée par la méthode de ma classe?

    À noter, j'utilise Visual Studio 2012 (VC11). Lorsqu'un collègue compile et exécute le code (XCode sous OSX) tout fonctionne sans problème.

    Est-ce que c'est un problème de compilateur qui ne prend pas en charge ce type d'opération de la façon que je croyais? C'est peut-être une fonctionnalité dans une version plus récente du standard...?

    Merci beaucoup!

  2. #2
    Rédacteur/Modérateur


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

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 147
    Billets dans le blog
    4
    Par défaut
    Il doit y avoir des "optimisations" puisque ta variable retournée est une copie et donc temporaire. Et VS11 doit "mal" les faire si tu dis que sur Xcode ça fonctionne.
    Transforme ta fonction pour avoir une meilleure signature const std::string& get() const { return _name; } et tu ne devrais plus avoir de problème. Sinon il te faudra utiliser une variable intermédiaire.
    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.

  3. #3
    Expert éminent

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 202
    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 202
    Par défaut
    En fait, c'est traitre. Tu tombes sur plusieurs détails en même temps.

    1. La fonction c_str() retourne un pointeur qui n'est valable que dans l'expression contenant son appel, ou à la rigueur jusqu'à ce que la string risque d'être modifiée (doc de c_str())
    2. En sql, bind n'est pas l'exécution de la requete, mais simplement l'attachement d'une valeur à une variable de la requete préparée.
    3. Un char* n'est pas une chaine de caractères, mais un pointeur vers une zone mémoire susceptible d'en contenir une. Tu noteras d'ailleurs qu'il y a une taille en argument de bind.
    4. La fonction string client::firstname() retourne une valeur temporaire.

    De plus, la signature de ta fonction, string client::firstname(), n'est pas const, ce qui empêche de l'appeler sur une référence constante.

    Quand tu écris sqlite3_bind_text(stmt, 1, client.firstname().c_str(), client.firstname().size(), SQLITE_STATIC);, tu bind un pointeur vers une variable temporaire.
    Lorsque cette instruction se termine, cette variable temporaire est détruite, et le pointeur n'est plus valable. Je suis plus surpris parce que ca n'introduise pas du bazar dans la base, plutot que rien.

    En passant par une variable locale, tu introduit une autre string, qui reste vivante apparemment jusqu'à l'exécution de la requete.

    Si ta fonction firstname() retournait une référence constante, tu n'aurais a priori plus ce problème.
    Essaie std::string const& client::firstname() const

  4. #4
    Membre à l'essai
    Inscrit en
    Août 2006
    Messages
    4
    Détails du profil
    Informations forums :
    Inscription : Août 2006
    Messages : 4
    Par défaut
    Merci pour vos commentaires et suggestions, c'est très instructif!
    Je vais tester le tout et je vous donnerai mes résultats.

  5. #5
    Membre à l'essai
    Inscrit en
    Août 2006
    Messages
    4
    Détails du profil
    Informations forums :
    Inscription : Août 2006
    Messages : 4
    Par défaut
    Super!
    Merci à vous deux, en modifiant la signature, ça fonctionne exactement comme je le souhait.

    J'ai besoin de beaucoup de pratique encore pour bien saisir les notions de pointeurs et constance...

  6. #6
    Expert éminent

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 202
    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 202
    Par défaut
    défini tout ce que tu peux comme const.
    Les références constantes (type const& variable) sont tes meilleures amies: pas de pointeur, pas de copie, pas de variation.
    Pour pouvoir les utiliser, il faut que les fonctions membres soient aussi constantes que possible.

    Les pointeurs, eux, sont à éviter quand c'est possible

  7. #7
    Expert confirmé
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 766
    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 766
    Par défaut
    Citation Envoyé par leternel Voir le message
    Les pointeurs, eux, sont à éviter quand c'est possible
    Bof , un pointeur peut être optionnel.

    Un 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
    RETURN_ID do_something(wstring* error_str) {
        RETURN_ID ret;
     
    //  Do Something
     
        if (error_str != NULL) {
            switch(ret) {
            case RET_NO_ERROR: (*error_str) = L""; break;
            case RET_ERROR_NO_DEVICE: (*error_str) = L"Please connect your device"; break;
     
    //        ....
            }
        }
     
        return ret;
    }

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

Discussions similaires

  1. Réponses: 1
    Dernier message: 19/10/2015, 14h52
  2. Réponses: 4
    Dernier message: 22/07/2014, 16h57
  3. Changer la valeur d'une variable avec "onClick"
    Par Tryp' dans le forum Langage
    Réponses: 6
    Dernier message: 06/06/2009, 18h50
  4. changer la valeur d'une variable avec 2 bouton
    Par toutounesan_bg dans le forum Balisage (X)HTML et validation W3C
    Réponses: 1
    Dernier message: 03/08/2007, 10h51
  5. Réponses: 13
    Dernier message: 30/05/2006, 16h00

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