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 :

déduction de type qui cause un segfault


Sujet :

C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre émérite
    Avatar de Daïmanu
    Homme Profil pro
    Développeur touche à tout
    Inscrit en
    Janvier 2011
    Messages
    734
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur touche à tout

    Informations forums :
    Inscription : Janvier 2011
    Messages : 734
    Par défaut déduction de type qui cause un segfault
    Bonjour.

    Je suis en train d'écrire une petite lib C++ qui manipule indifféremment des std::string, des std::wstring et plus généralement n’importe quel std::basic_string<CharT>.
    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
    #include <string>
    #include <sstream>
    #include <iostream>
    #include <utility>
     
    template<class CharT>
    class Text {
    	public:
    		typedef std::basic_string<CharT> String;
     
    		Text(const String& str) {
    			std::cout << "Text()\n";
    			append(str);
    		}
    		~Text() {
    			std::cout << "~Text()\n";
    		}
    		Text(const Text&) = delete;
    		Text(Text && other) {
    			std::cout << "Text(&&)\n";
    			std::move(other.oss);
    		}
     
    		Text& append(const String& str) {
    			std::cout << "append()\n";
    			oss << str;
    			return (*this);
    		}
     
    		String get() const {
    			std::cout << "get()\n";
    			return oss.str();
    		}
     
    	private:
    		std::basic_ostringstream<CharT> oss;
    };
     
    template<class CharT>
    Text<CharT>&& createText(const std::basic_string<CharT>& str) {
    	std::cout << "createText()\n";
    	return std::move(Text<CharT>(str));
    }
    J'ai la fonction createText() pour déduire automatiquement le type de string et éviter à l'utilisateur d'avoir à l'écrire.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    int main(int, char **) {
    	std::string str = "Hello";
    	auto t = createText(str);
    	std::cout << t.append(" World").get() << std::endl;
    }
    Avec ce main, il n'y a pas de problèmes.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    int main(int, char **) {
    	std::string str = "Hello";
    	std::cout << createText(str).append(" World").get() << std::endl;
    }
    Alors que celui-ci provoque un segfault, il semblerai que l'objet Text retourné par createText() soit détruit juste après qu'il ait été créé.
    createText()
    Text()
    append()
    ~Text()
    append()
    get()
    Erreur de segmentation (core dumped)
    Et je n'arrive pas à expliquer pourquoi, est-ce que c'est du à l'utilisation de la sémantique de mouvement ?
    Est-ce qu'il y a moyen de rendre la deuxième syntaxe utilisable ?
    Par ailleurs, est-ce qu'il est possible que le code s'adapte entre cout et wcout automatiquement ?

    Cordialement.

  2. #2
    Membre Expert

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Avril 2013
    Messages
    610
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Finance

    Informations forums :
    Inscription : Avril 2013
    Messages : 610
    Billets dans le blog
    21
    Par défaut
    Oui, c'est bien dû à la sémantique de mouvement.
    La règle, c'est qu'il ne faut pas appliquer std::move pour retourner un objet local non statique.
    En effet:
    - de toute façon, l'optimisation est automatique si l'objet en question a un constructeur de mouvement (cf NRVO)
    - les références à des rvalues restent des références; comme l'objet est détruit à la sortie de la fonction, la référence est à un objet détruit -> d'où le segfault.

  3. #3
    Membre émérite
    Avatar de Daïmanu
    Homme Profil pro
    Développeur touche à tout
    Inscrit en
    Janvier 2011
    Messages
    734
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur touche à tout

    Informations forums :
    Inscription : Janvier 2011
    Messages : 734
    Par défaut
    Ah, j'ignorai que le déplacement de variable locale était automatique, c'est pour ça que je suis parti directement sur du move.
    En effet, en enlevant la rvalue reference ça marche mieux.

    Il reste le problème d'adapter std::(w)cout en fonction du paramètre template CharT. Est-ce que c'est possible ?

    Cordialement.

  4. #4
    Membre éclairé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2010
    Messages
    517
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gironde (Aquitaine)

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

    Informations forums :
    Inscription : Avril 2010
    Messages : 517
    Par défaut
    Salut,

    Tu peux utiliser std::enable_if pour activer une méthode en fonction de tel ou tel paramètre/type de données:

    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
    #include <string>
    #include <sstream>
    #include <iostream>
    #include <utility>
     
    template<typename CharT>
    class Text {
    	public:
    		typedef std::basic_string<CharT> String;
     
    		Text(const String& str) {
    			std::cout << "Text()\n";
    			append(str);
    		}
    		~Text() {
    			std::cout << "~Text()\n";
    		}
    		Text(const Text&) = delete;
    		Text(Text && other) {
    			std::cout << "Text(&&)\n";
    			std::move(other.oss);
    		}
     
    		Text& append(const String& str) {
    			std::cout << "append()\n";
    			oss << str;
    			return (*this);
    		}
     
    		String get() const {
    			std::cout << "get()\n";
    			return oss.str();
    		}
     
        template<typename Char=CharT>
        //Méthode utilisée seulement si CharT == wchar_t
        typename std::enable_if<std::is_same<Char, wchar_t>::value, void>::type
        print() const {
             std::wcout << oss.str();
        }
     
        template<typename Char=CharT>
        //Méthode utilisée seulement si CharT == char_t
        typename std::enable_if<std::is_same<Char, char>::value, void>::type
        print() const {
             std::cout << oss.str();
        }
     
        template<typename Char=CharT>
        //Méthode utilisée seulement si CharT != wchar_t && CharT != char_t (en gros la méthode par défaut)
        typename std::enable_if<!(std::is_same<Char, wchar_t>::value) &&
                                !(std::is_same<Char, char>::value), void>::type
        print() const {
             std::cout << oss.str();
        }
     
     
    	private:
    		std::basic_ostringstream<CharT> oss;
    };
     
    template<typename CharT>
    Text<CharT> createText(const std::basic_string<CharT>& str) {
    	std::cout << "createText()\n";
    	return Text<CharT>(str);
    }
    Et tu l'utiliserais de cette façon:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    int main(int, char **) {
    	std::string str = "Hello";
    	std::string world = " World\n";
      createText(str).append(world).print();
     
    	std::wstring wstr(str.begin(), str.end());
      std::wstring wWorld(world.begin(), world.end());
    	createText(wstr).append(wWorld).print();
            std::cout << std::endl;
    }
    J'ai testé avec le compilateur clang et je pense qu'avec gcc ça fonctionnera aussi. Par contre aucune idée pour le compilateur de VS.

  5. #5
    Membre émérite
    Avatar de Daïmanu
    Homme Profil pro
    Développeur touche à tout
    Inscrit en
    Janvier 2011
    Messages
    734
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur touche à tout

    Informations forums :
    Inscription : Janvier 2011
    Messages : 734
    Par défaut
    Merci beaucoup, c'est précisément ce dont j'avais besoin.

    J'ai juste remplacé print par un opérateur (), mais ça fonctionne avec gcc.

    Cordialement.

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

Discussions similaires

  1. Type qui correspond à l'objet reel.
    Par Ekinoks dans le forum C++
    Réponses: 21
    Dernier message: 10/07/2008, 18h22
  2. [SQL2005] Requète qui cause problème
    Par Dohmaker dans le forum Développement
    Réponses: 4
    Dernier message: 05/05/2008, 23h25
  3. transtypage dans un type qui varie
    Par Braillane dans le forum C#
    Réponses: 5
    Dernier message: 26/09/2007, 17h08
  4. Réponses: 1
    Dernier message: 05/09/2007, 22h50
  5. Requete SELECT qui cause une erreur SQL
    Par ahage4x4 dans le forum ASP
    Réponses: 23
    Dernier message: 10/06/2005, 14h46

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