2016-03-08 2 views
-1

У меня есть «сообщение» класса, среди прочих, члены:Почему getline() не работает в моем коде (C++)?

protected: 
     int * next; 
     int amount; 
     std::string ** mes; 
public: 
     message(std::ifstream*); 

и код для конструктора:

message :: message(ifstream * myfile){ 
    *myfile >> amount; 
    if (amount==0){ 
       next = new int[1]; 
       *myfile >> next[0]; 
       mes = new string*[1]; 
       getline(*myfile,*mes[0]); 
       } 
    else{ 
       next = new int[amount]; 
       mes = new string*[amount]; 
       for (int i=0;i<amount;i++){ 
        *myfile >> next[i]; 
        getline(*myfile,*mes[i]); 
        } 
       } 
    } 

Чтение из файла с помощью оператора >> работает просто отлично, но программа падает на getline() - почему? Что я должен изменить?

+8

Любая причина * не * использовать 'std :: vector ', вместо того чтобы делать все это руководство, подверженное ошибкам динамическое распределение? –

+2

Вы можете столкнуться с этой проблемой после устранения сбоя: [C++ - Почему std :: getline() пропускает вход после форматированного извлечения? - Переполнение стека] (http://stackoverflow.com/questions/21567291/why-does-stdgetline-skip-input-after-a-formatted-extraction) – MikeCAT

+0

Пропускать потоки по ссылке не указателями. Это уменьшает вероятность возникновения дефектов указателями, указывающими на неправильные местоположения. –

ответ

2

Вы не выделяете какую-либо память для переменных std::string, которые вы запрашиваете std::getline() для чтения. Вы выделяете массивы указателей string*, которые не указывают ни на что. Вы должны изменить свой код либо:

  1. донжон, используя массив указателей, но выделить фактические string переменные для них:

    std::string ** mes; 
    

    if (amount == 0) { 
        ... 
        mes = new string*[1]; 
        mes[0] = new string; // <-- here 
        std::getline(*myfile, *mes[0]); 
    } 
    else { 
        ... 
        mes = new string*[amount]; 
        for (int i = 0; i < amount; ++i) { 
         mes = new string[amount]; // <-- here 
        } 
        for (int i = 0; i < amount; ++i) { 
         ... 
         std::getline(*myfile, *mes[i]); 
        } 
    } 
    
  2. удалить ненужное уровень косвенности для начала:

    std::string * mes; 
    

    if (amount == 0) { 
        ... 
        mes = new string[1]; 
        std::getline(*myfile, mes[0]); 
    } 
    else{ 
        ... 
        mes = new string[amount]; 
        for (int i = 0; i < amount; ++i) { 
         ... 
         std::getline(*myfile, mes[i]); 
        } 
    } 
    

Wit, который сказал, вы должны прекратить использовать сырые массивы, чтобы начать с, и вместо того, чтобы использовать std::vector:

#include <vector> 

protected: 
    std::vector<int> next; 
    std::vector<std::string> mes; 
    int amount; 

message :: message(ifstream * myfile) { 
    *myfile >> amount; 
    if (amount == 0) { 
     next.resize(1); 
     mes.resize(1); 
     *myfile >> next[0]; 
     std::getline(*myfile, mes[0]); 
    } 
    else { 
     next.resize(amount); 
     mes.resize(amount); 
     for (int i = 0; i < amount; ++i) { 
      *myfile >> next[i]; 
      std::getline(*myfile, mes[i]); 
     } 
    } 
} 

В любом случае, вы следует рассмотреть возможность избавления от избыточного кода для amount == 0 кейс. Используйте локальную переменную и установите его в 1, если amount является 0, в противном случае установите его фактического amount, а затем вы можете использовать одну строку кода для выполнения распределения независимо от amount значения:

message :: message(ifstream * myfile) { 
    *myfile >> amount; 
    int numElements = (amount == 0) ? 1 : amount; 
    next = new int[numElements]; 
    mes = new string[numElements]; 
    for (int i = 0; i < numElements; ++i) { 
     *myfile >> next[i]; 
     getline(*myfile, mes[i]); 
    } 
} 

message :: message(ifstream * myfile) { 
    *myfile >> amount; 
    int numElements = (amount == 0) ? 1 : amount; 
    next.reserve(numElements); 
    mes.reserve(numElements); 
    for (int i = 0; i < numElements; ++i) { 
     int value; 
     *myfile >> value; 
     next.push_back(value); 
     std::string line; 
     std::getline(*myfile, line); 
     mes.push_back(line); 
    } 
} 
+0

Прежде всего, спасибо. Я пошел с решением 2. потому что, как я понял, косвенность действительно не нужна в этот момент. Я обычно пропускаю большие объекты в этой программе все время, поэтому я попытался использовать массивы указателей для повышения эффективности, но просто для нескольких строк, которые не были необходимы. Я пытаюсь частично использовать свои собственные классы с элементами массива. На моем uni в первый год они в основном запрещают вам использовать std :: vector, поэтому вы можете понять, как работают массивы.После этого вы можете использовать std :: vector. – user3019593

+0

Кроме того, сумма == 0 случай абсолютно не избыточна (хотя это не так заметно в конструкторе). Вместо добавления другой логической переменной количество, равное нулю, указывает на определенное состояние: сообщение с количеством 0 и сообщение с количеством 1 будут обрабатываться совсем по-другому, даже если они имеют одинаковое фактическое количество строк в массиве. В частности, представьте диалог в старой игре, такой как ворота Бальдура или «Самое длинное путешествие». Сумма == 0 означает простое сообщение, которое приведет к следующему при каждом нажатии, а сумма> 0 предложит пользователю выбрать ответ (даже если есть только один). – user3019593

+0

Даже если остальная часть класса обрабатывает 'amount == 0' по-разному, для целей конструктора, выделяющего массивы, нет никакой разницы. Я обновил свой пример, чтобы отразить это, используя временную переменную, поэтому 'amount' останется 0. –

Смежные вопросы