C ++ getline segmentation fault,std :: vector <custom class =“”>

时间:2015-05-14 21:20:12

标签: c++ ifstream stdvector getline

我一直在调试器中查看这一段时间谷歌搜索,但我想我偶然发现了一些我不熟悉的C ++行为。我将简要介绍一下我正在做什么,问题是什么/在哪里。我将把代码块放在下面。

正在发生的事情的大致概述是:

  1. 创建了一个自定义类(LogReader)来处理单个日志文件。
  2. LogReader包含指向ifstream(ifstream * log_file)
  3. 的指针
  4. ifstream与构造函数中的getline()一起使用,这很好。
  5. LogReader放在向量中。
    • main.cpp的以下代码直接使用LogReader(没有向量)。两种情况都会发生段错误。
  6. 调用LogReader.advance()。 getline()用于此函数。此处发生了段错误(在LogReader.cpp中注释)。
  7. 感谢您对我所遗漏的可能导致此问题的C ++行为的任何帮助!

    编辑:不将LogReader放入向量中会删除段错误(现在在其他地方失败,但不是问题)。更改是在main.cpp

    中注释以下行
    readers.push_back(&label_reader);
    

    我想现在的问题是为什么使用std :: vector会导致这个问题。

    LogReader.h

    #ifndef LOGREADER
    #define LOGREADER
    
    using namespace std;
    
    class LogReader {
         private:
             LogReader(){} // private default constructor
    
         public:
             ifstream *log_file; // file the log is read from
             vector<int> val_locations; // offsets in line for values
             string next_line; // next line from the file
    
             int current_time; // time for most recent reading
             string current_line;
             int next_time; // what is the next time in the file
             vector<string> current_vals; // what the current vals are
    
             LogReader(string log_loc, vector<int> offsets); // given a file to start on
    
             bool advance(int new_time); // advance the log reader, return true if advanced
             bool has_more(); // is there more in the log
     };
    
     #endif
    

    LogReader.cpp

    // c++ imports
    #include <boost/algorithm/string.hpp>
    #include <fstream>
    #include <iostream>
    #include <string>
    #include <vector>
    
    // my imports
    #include "LogReader.h"
    #include "functions.h"
    
    using namespace std;
    
    LogReader::LogReader(string log_loc, vector<int> offsets){
        // make the file reader
        ifstream lf(log_loc);
        log_file = &lf;
        // pull out the first line
        getline(*log_file, current_line);
        cout << current_line << endl;
    
        // get the set of current values
        val_locations = offsets;
        for(int i = 0; i < val_locations.size(); i++) {
            current_vals.push_back(get_line_part(current_line, 
                        val_locations.at(i)));
        }
        // get the current time
        current_time = stoi(get_line_part(current_line, 0));
    
        // pull down the next line
        getline(*log_file, next_line);
        cout << next_line << endl;
        // get the next time
        next_time = stoi(get_line_part(next_line, 0));
    }
    
    bool LogReader::advance(int new_time){
        if(new_time < next_time)
            return false; // nothing to do, current still good
    
        cout << "can check time" << endl;
    
        // update the time and values
        current_time = next_time;
        current_line = next_line;
        current_vals.clear();
    
        cout << "can do housekeeping" << endl;
    
        for(int i = 0; i < val_locations.size(); i++) {
            current_vals.push_back(get_line_part(next_line, 
                        val_locations.at(i)));
        }
    
        cout << "can push in new values" << endl;
    
        // move the line
        next_line.clear();
        if(!getline(*log_file, next_line)) {  // **SEGFAULT**
            // no more lines
            cout << "no more lines" << endl;
            next_line.clear();
            next_time = -1;
            return true;
        }
        cout << "got the line" << endl;
        // update the time as well
        next_time = stoi(get_line_part(next_line, 0));
        return true;
    }
    
    bool LogReader::has_more(){
        return next_time != -1;
    }
    

    的main.cpp

    // c imports
    #include <time.h>
    
    // c++ imports
    #include <algorithm>
    #include <boost/algorithm/string.hpp>
    #include <boost/date_time.hpp>
    #include <boost/date_time/posix_time/posix_time.hpp>
    #include <boost/filesystem.hpp>
    #include <fstream>
    #include <iostream>
    #include <string>
    #include <sstream>
    #include <vector>
    
    // my imports
    #include "LogReader.h"
    #include "functions.h"
    
    // custom shorter namespaces
    namespace bfs = boost::filesystem;
    
    // used namespaces
    using namespace std;
    
    void update_line(int *current_time, string *current_line, 
            ifstream *current_file){
        if(!getline(*current_file, *current_line)){
            *current_time = -1;
            current_line->clear();
            return;
        }
    
        try {
            *current_time = stoi(get_line_part(*current_line, 0));
        } catch (int e) {
            cout << "update line, bad stoi on time" << endl;
            cout << *current_line << endl;
            throw e;
        }
    }
    
    void update_vals(vector<float*> vals, string line) {
        for(int i = 0; i < vals.size(); i++) {
            // offset for fact that first two are time and sensor
            try {
                *(vals.at(i)) = stof(get_line_part(line, 2 + i));
            } catch (int e) {
                cout << "update_vals, bad stof for " << i << endl;
                cout << line << endl;
                throw e;
            }
        }
    }
    
    string get_correct_file(string name, vector<string> options) {
        for(int i =0; i < options.size(); i++) {
            string option = options.at(i);
            if(boost::algorithm::contains(option, name)){
                return option;
            }
        }
    
        return string("");
    }
    
    int main(int argc, char* argv[]) {
        // open the base dir
        bfs::path base_dir("log/");
        if(!bfs::exists(base_dir) && !bfs::is_directory(base_dir)){
            cout << "Bad base directory" << endl;
            return 1;
        }
    
        // create a vector of the possible traces
        vector<string> traces;
        for(bfs::directory_iterator iter(base_dir);
                iter != bfs::directory_iterator(); iter++) {
            stringstream trace_path;
            trace_path << iter->path().string();
            traces.push_back(trace_path.str());
        }
    
        int trace_index = user_choose_option(traces);
    
        // load that directory
        bfs::path trace_dir(traces.at(trace_index));
        if(!bfs::exists(base_dir) && !bfs::is_directory(base_dir)){
            cout << "Selected a bad trace directory" << endl;
            return 1;
        }
    
        // get the image directory
        cout << "loading image directory" << endl;
        string img_path_string = trace_dir.string();
        stringstream img_path_stream;
        img_path_stream << img_path_string << "/img/";
        bfs::path img_dir(img_path_stream.str());
        if(!bfs::exists(img_dir) && !bfs::is_directory(img_dir)){
            cout << "no image directory" << endl;
            return 1;
        }
    
        // get image list, ends up in sorted order from naming conventions
        cout << "getting image paths" << endl;
        vector<string> image_paths;
        for(bfs::directory_iterator iter(img_dir);
                iter != bfs::directory_iterator(); iter++) {
            stringstream image_path;
            image_path << iter->path().string();
            image_paths.push_back(image_path.str());
        }
    
        // get the data traces
        cout << "loading data traces" << endl;
        vector<string> log_paths;
        vector<string> label_paths;
        string trace_path_string = trace_dir.string();
        for(bfs::directory_iterator iter(trace_path_string);
                iter != bfs::directory_iterator(); iter++) {
            string cur_file = iter->path().string();
            cout << cur_file << endl;
            if(boost::algorithm::contains(cur_file, "label-")) {
                label_paths.push_back(cur_file);
            } else if(boost::algorithm::contains(cur_file, "log-")) {
                log_paths.push_back(cur_file);
            }
        }
        cout << endl;
    
        // temp for reading in line parts
        // istringstream temp;
    
        cout << "getting log readers" << endl;
        // choose the label file to use, get first line
        int label_index = user_choose_option(label_paths);
        vector<int> label_offsets;
        label_offsets.push_back(1);
        LogReader label_reader(label_paths.at(label_index), label_offsets);
        /*
        ifstream label_file(label_paths.at(label_index));
        string label_line;
        getline(label_file, label_line);
        int label_time;
        temp.clear();
        temp.str(get_line_part(label_line, 0));
        temp >> label_time;
        string label_current = get_line_part(label_line, 1);
        */
    
        /*
        // get the accel
        string accel_path = get_correct_file("accel", log_paths);
        vector<int> accel_offsets;
        accel_offsets.push_back(2);
        accel_offsets.push_back(3);
        accel_offsets.push_back(4);
        LogReader accel_reader(accel_path, accel_offsets);
        */
    
        vector<LogReader*> readers;
        vector<bool> updated;
        readers.push_back(&label_reader);
        updated.push_back(true);
    //    readers.push_back(&accel_reader);
    //    updated.push_back(true);
    
        int l_time = current_time_min(readers);
        while(label_reader.has_more() ){ // || accel_reader.has_more()) {
            // figure out what time to advance to
            int n_time;
            cout << label_reader.has_more() << endl;
            if(same_current_time(readers)) {
                n_time = next_time_min(readers);
            } else {
                n_time = current_time_nextmin(readers);
            }
            cout << n_time << endl;
    
            label_reader.advance(n_time);
            cout << label_reader.current_line << endl;
            /*
            // advance all the readers
            for(int i = 0; i < readers.size(); i++) {
                cout << "loop " << i << endl;
                // keep track of which values updated
                readers.at(i);
                cout << "can get from vector" << endl;
                bool advanced = readers.at(i)->advance(n_time);
                cout << advanced << endl;
                if(advanced) {
                    updated.at(i) = true;
                } else {
                    updated.at(i) = false;
                }
            }
    
            // sanity check printing
            for(int i = 0; i < readers.size(); i++) {
                cout << readers.at(i)->current_line << endl;
            }
            */
    
            // deal with statistics here
    
        }
    
        /*
        ifstream accel_file(accel_path);
        string accel_line;
        getline(accel_file, accel_line);
        int accel_time;
        temp.clear();
        temp.str(get_line_part(accel_line, 0));
        temp >> accel_time;
        float accel_current_x = stof(get_line_part(accel_line, 2));
        float accel_current_y = stof(get_line_part(accel_line, 3));
        float accel_current_z = stof(get_line_part(accel_line, 4));
        vector<float*> accel_vals;
        accel_vals.push_back(&accel_current_x);
        accel_vals.push_back(&accel_current_y);
        accel_vals.push_back(&accel_current_z);
    
        // get the sprox
        string sprox_path = get_correct_file("sprox", log_paths);
        ifstream sprox_file(sprox_path);
        string sprox_line;
        getline(sprox_file, sprox_line);
        int sprox_time;
        temp.clear();
        temp.str(get_line_part(sprox_line, 0));
        temp >> sprox_time;
        float sprox_current = stof(get_line_part(sprox_line, 2));
        vector<float*> sprox_vals;
        sprox_vals.push_back(&sprox_current);
    
        // get the lprox
        string lprox_path = get_correct_file("lprox", log_paths);
        ifstream lprox_file(lprox_path);
        string lprox_line;
        getline(lprox_file, lprox_line);
        int lprox_time;
        temp.clear();
        temp.str(get_line_part(lprox_line, 0));
        temp >> lprox_time;
        float lprox_current = stof(get_line_part(lprox_line, 2));
        vector<float*> lprox_vals;
        lprox_vals.push_back(&lprox_current);
    
        // get the light
        string light_path = get_correct_file("light", log_paths);
        ifstream light_file(light_path);
        string light_line;
        getline(light_file, light_line);
        int light_time;
        temp.clear();
        temp.str(get_line_part(light_line, 0));
        temp >> light_time;
        float light_current = stof(get_line_part(light_line, 2));
        vector<float*> light_vals;
        light_vals.push_back(&light_current);
        */
    
    //    int time_current = min(label_time, min(sprox_time, 
    //                min(lprox_time, min(accel_time, 
    //                light_time))));
    
        /*
        // variables for processing here
        int total_time = 0;
        map<string, int> label_counts;
    
        while(label_time != -1 || accel_time != -1 || sprox_time != -1
                || lprox_time != -1 || light_time != -1) {
            time_current++;
            if(label_time != -1 && time_current > label_time) {
                update_line(&label_time, &label_line, &label_file);
                if(label_line.size() > 0) // if last label, don't overwrite
                    label_current = get_line_part(label_line, 1);
            }
            if(accel_time != -1 && time_current > accel_time) {
                update_line(&accel_time, &accel_line, &accel_file);
                if(accel_line.size() > 0) // if last line, don't overwrite
                    update_vals(accel_vals, accel_line);
            }
            if(sprox_time != -1 && time_current > sprox_time) {
                update_line(&sprox_time, &sprox_line, &sprox_file);
                if(sprox_line.size() > 0) // if last line, don't overwrite
                    update_vals(sprox_vals, sprox_line);
            }
            if(lprox_time != -1 && time_current > lprox_time) {
                update_line(&lprox_time, &lprox_line, &lprox_file);
                if(lprox_line.size() > 0) // if last line, don't overwrite
                    update_vals(lprox_vals, lprox_line);
            }
            if(light_time != -1 && time_current > light_time) {
                update_line(&light_time, &light_line, &light_file);
                if(light_line.size() > 0) // if last line, don't overwrite
                    update_vals(light_vals, light_line);
            }
    
            // Processing happens here
            total_time++;
            if(label_counts.count(label_current) == 0)
                // not in map
                label_counts[label_current] = 0;
            label_counts[label_current]++;
        }
    
        // post processing happens here
        cout << "Labels Counts:" << endl;
        for(map<string, int>::iterator it = label_counts.begin(); 
                it != label_counts.end(); it++) {
            cout << it->first << " -> " << it->second << " -> ";
            cout << 1.0 * it->second / total_time << endl;
        }
        */
    }
    

1 个答案:

答案 0 :(得分:2)

您的程序显示未定义的行为,因为您正在使用指向已删除对象的指针。

ifstream lf(log_loc);
log_file = &lf;

if在构造函数返回时被删除,并且您仍然保持指向该对象的指针。

log_file更改为对象而不是指针。