Partage
  • Partager sur Facebook
  • Partager sur Twitter

[Segmentation Fault] std::getline

Sujet résolu
    7 août 2020 à 11:09:42

    Bonjour bonjour!

    ça fait maintenant 2 jours que je suis bloqué là-dessus et je commence à en avoir marre *soupir*... du coup je viens voir si pourrais obtenir de l'aide ici :)

    Contexte : Je suis pas très bon en C++ mais j'ai un projet à faire sur une Nucleo STM32F401RE sous Mbed. Une partie du code doit se contenter de lire le contenu d'un classeur CSV et traiter des infos. Je n'ai pas encore le matériel pour mettre le CSV sur la nucleo, donc je le simule avec un flux créé à partir d'une string (CSVCONTENT)

    Problème : J'ai récupéré un super code sur StackOverflow pour traiter les flux CSV ici et j'ai ma classe Scenario qui a un (pointeur sur) CSVIterator en attribut. Je peux afficher sans problème le contenu de celui-ci, mais dès que je fais appel à l'opérateur ++, l'appel à std::getline dans CSVRow::readNextRow résulte en une erreur de segmentation... Mais si je reproduit le même comportement avec un CSVIterator qui se trouve directement dans le main, j'ai aucun problème. Je n'arrive pas à voir d'où peut venir l'erreur...

    Ci-joint le code:

    CSVReader.hpp

    #ifndef CSVREADER_HPP
    #define CSVREADER_HPP
    
    
    #include <iterator>
    #include <iostream>
    #include <fstream>
    #include <sstream>
    #include <vector>
    #include <string>
    
    class CSVRow
    {
        public:
            std::string_view operator[](std::size_t index) const
            {
                return std::string_view(&m_line[m_data[index] + 1], m_data[index + 1] -  (m_data[index] + 1));
            }
            std::size_t size() const
            {
                return m_data.size() - 1;
            }
            void readNextRow(std::istream& str)
            {
                std::getline(str, m_line);
    
                m_data.clear();
                m_data.emplace_back(-1);
                std::string::size_type pos = 0;
                while((pos = m_line.find(';', pos)) != std::string::npos) //modified : ',' to ';' for my csv format
                {
                    m_data.emplace_back(pos);
                    ++pos;
                }
                // This checks for a trailing comma with no data after it.
                pos   = m_line.size();
                m_data.emplace_back(pos);
            }
        private:
            std::string         m_line;
            std::vector<int>    m_data;
    };
    
    inline std::istream& operator>>(std::istream& str, CSVRow& data)
    {
        data.readNextRow(str);
        return str;
    }
    
    
    class CSVIterator
    {   
        public:
            typedef std::input_iterator_tag     iterator_category;
            typedef CSVRow                      value_type;
            typedef std::size_t                 difference_type;
            typedef CSVRow*                     pointer;
            typedef CSVRow&                     reference;
    
            CSVIterator(std::istream& str)  :m_str(str.good()?&str:NULL) { ++(*this); }
            CSVIterator()                   :m_str(NULL) {}
    
            // Pre Increment
            CSVIterator& operator++()               {if (m_str) { if (!((*m_str) >> m_row)){m_str = NULL;}}return *this;}
            // Post increment
            CSVIterator operator++(int)             {CSVIterator    tmp(*this);++(*this);return tmp;}
            CSVRow const& operator*()   const       {return m_row;}
            CSVRow const* operator->()  const       {return &m_row;}
    
            bool operator==(CSVIterator const& rhs) {return ((this == &rhs) || ((this->m_str == NULL) && (rhs.m_str == NULL)));}
            bool operator!=(CSVIterator const& rhs) {return !((*this) == rhs);}
        private:
            std::istream*       m_str;
            CSVRow              m_row;
    };
    
    class CSVRange
    {
        std::istream&   stream;
        public:
            CSVRange(std::istream& str)
                : stream(str)
            {}
            inline void foo(){
                std::cout << "coucou\n";
                }
            
            CSVIterator begin() const {return CSVIterator{stream};}
            CSVIterator end()   const {return CSVIterator{};}
    };
    
    #endif

    Scenario.hpp & .cpp

    #ifndef SCENARIO_HPP
    #define SCENARIO_HPP
    
    #include "CSVReader.hpp"
    #include "rtos.h"
    
        
    const std::string CSVCONTENT = "01/01/2020;12:00;1000.0\n"
    "01/01/2020;12:10;1750.0\n"
    "01/01/2020;12:20;2500.0\n"
    "01/01/2020;12:30;3250.0\n";
        
    class Scenario{
        public:
            //methods
            Scenario();
            void next();
        private:
            CSVIterator* m_csv;
            double m_nextValue;
        
    };
    
    #endif
    
    
    
    #include "Scenario.hpp"
    #include <sstream>
    
    
    Scenario::Scenario(){
        printf("init Scenario\n");
        
        std::cout << "no such file\n";
        std::istringstream is(CSVCONTENT);
        
        this->m_csv = new CSVIterator(is);
            
    }
    
    
    void Scenario::next(){
        std::cout << (**this->m_csv)[2] << "\n"; //ok
        (*this->m_csv)++; //error
    }

    main.cpp (qui fait les deux comportement, d'abord celui sans erreur avec le CSVIterator du main, puis avec erreur avec celui de Scenario)

    #include "mbed.h"
    #include "rtos.h"
    #include "platform/mbed_thread.h"
    
    #include "CSVReader.hpp"
    #include "Scenario.hpp"
    // Blinking rate in milliseconds
    #define BLINKING_RATE_MS                                                    500
    
    DigitalIn button(PC_13);
    
    int main()
    {
        //task_wait.start(waitingForReset);
        Scenario scenar;
    
        std::istringstream is(CSVCONTENT);
        CSVIterator* main_csv = new CSVIterator(is);
    
        while(true){
            if(button.read() == 0){
    
                cout << "directly in the main\n";
    
                //same code in scenario::next
                std::cout << (**main_csv)[2] << "\n"; //ok
                (*main_csv)++; //ok
    
                cout << "in the scenario class\n";
    
                scenar.next(); //error
                ThisThread::sleep_for(BLINKING_RATE_MS);
            }
        }
    }

    Merci d'avance si vous arrivez à m'expliquer ce phénomène :)



    -
    Edité par WexyR 7 août 2020 à 11:28:40

    • Partager sur Facebook
    • Partager sur Twitter
    Si je suis tête en l'air, c'est par habitude de viser le sommet
      7 août 2020 à 12:10:39

      Salut,

      Dans une classe, sauf pour raison d'ambiguité, tu n'as pas besoin pas besoin d'utiliser le pointeur this.

      Et pourquoi ne fais-tu pas une instanciation automatique de ton itérateur ? Ca t'évitera les casse tête des multiple déréférencement, et ce sera plus lisible (en plus tu as une belle fuite de mémoire).

      PS: En C++ moderne, l'utilisation de l'opérateur new est une pratique en voie de disparition, on préfère s'en passer autant que possible.
      La librairie standard nous offre suffisamment d'outils pour cela (les pointeurs intelligents entre autre).

      • Partager sur Facebook
      • Partager sur Twitter
        7 août 2020 à 14:00:15

        Désolé ça faisait trop longtemps que j'avais pas codé en C++, j'ai effectivement codé un peu bizarrement..

        J'ai testé avec des smart pointeur mais j'obtenais la même erreur de segmentation. En fait je voulais un pointeur pouvoir l'initialiser dans le constructeur et pas la liste d'initialisation pour pouvoir tester correctement si je selectionne le flux du fichier ou de la string. Mais bon quand j'y repense, ce test devrait être fait en amont parce que c'est pas l'objectif de la classe Scenario.

        Correction : Ne pas utiliser de pointeur et faire l'instanciation automatiquement via la liste d'initialisation

        En bref j'ai juste codé un peu avec le c*l x) désolé pour ça et merci de ton aide :)

        case closed :)

        • Partager sur Facebook
        • Partager sur Twitter
        Si je suis tête en l'air, c'est par habitude de viser le sommet

        [Segmentation Fault] std::getline

        × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
        × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
        • Editeur
        • Markdown