2013-04-06 4 views
3

Я читаю свои структуры из файла, и я хотел бы добавить их в вектор structs. Вот как это выглядит и работает:Вектор structs: добавление элементов C++

typedef struct 
{ 
    int ID; 
    string name; 
    string surname; 
    int points; 
} 
Student; 

int main() 
{ 
    ifstream theFile("test.txt"); 
    std::vector<Student*> students; 

    Student* s = new Student(); 

    while(theFile >> s->ID >> s->name >> s->surname >> s->points) 
    { 
     studenti.push_back(s); // here I would like to add this struct s from a file 
    } 

// here I want to print each struct's values on the screen, but the output is always ONLY last struct N times, and not all of them, each only once 


    std::vector<Student*>::const_iterator it; 
    for(it = students.begin(); it != students.end(); it+=1) 
    { 
     std::cout << (*it)->ID <<" " << (*it)->name << " " << (*it)->surname <<" " << (*it)->points <<endl; 
    } 

Что я должен сделать, чтобы я мог добавить свои структур к вектору, и распечатать их, как правило (это печать только проверка на самом деле, если структуры являются правильно загружены в вектор)?

+2

Почему о '' typedef'? –

+1

И какой формат файла? Каждое имя ученика состоит из двух слов? –

+0

Обратите внимание, что у вас нет вектора structs, у вас есть вектор указателей. Все это указывает на тот же объект ... – juanchopanza

ответ

8

Вот как код может выглядеть в современном C++:

#include <string> 
#include <istream> 
#include <vector> 

struct Student 
{ 
    int ID; 
    std::string name; 
    std::string surname; 
    int points; 

    Student(int i, std::string n, std::string s, int p) 
    : ID(i), name(std::move(n)), surname(std::move(s)), points(p) {} 
}; 

std::vector<Student> read_students(std::istream & is) 
{ 
    std::vector<Student> result; 

    std::string name, surname; 
    int id, points; 

    while (is >> id >> name >> surname >> points) 
    { 
     result.emplace_back(id, name, surname, points); 
    } 

    return result; 
} 

Использование:

#include <fstream> 
#include <iostream> 

int main() 
{ 
    std::ifstream infile("test.txt"); 
    auto students = read_students(infile); 

    // ... 
} 
+1

Я попробовал emplace_back() структуру с четырьмя полями, как в вашем примере выше, но во время компиляции я получаю ошибку «нет подходящего конструктора», поэтому приведенный вами пример кажется неправильным. – kometen

+2

@ kometen: Вы правы: «Студент» нуждается в соответствующем конструкторе. Я добавил один. Кроме того, вы можете сказать 'result.push_back ({id, name, surname, points});' и вам не нужно добавлять конструктор для этой версии. –

+0

Очень элегантное решение. Спасибо. – kometen

8

Ваша ошибка состоит в том, чтобы использовать указатели

std::vector<Student> students; 

Student s; 
while(theFile >> s.ID >> s.name >> s.surname >> s.points) 
{ 
    students.push_back(s); 
} 

Теперь он будет работать.

Проблема была в том, что вы повторно использовали тот же указатель снова и снова. Таким образом, вы получаете вектор указателей, указывающих на один и тот же объект. Который будет иметь значения для последнего ученика, который читается.

Похоже, довольно распространенная новичка, чтобы выбрать сложную альтернативу, когда более простой из них правильный, поэтому мне было бы интересно узнать, почему вы решили использовать указатели.

+2

+1 для рекомендации не хранить указатели. –

+0

Я думал, что было бы лучше, если бы я использовал указатели, так как мне нужно вызвать методы в этом списке позже в программе. Но я не знаком с указателями, и это была просто идея. Не уверен в плюсах и минусах указателей, на самом деле. – Whizzil

+0

Вы можете вызывать методы в списке без использования указателей. Это не имеет значения, например. 'Студентов [я] .some_method();'. – john

0

Поскольку вы хотите хранить указатели на студентов, но не студенты в векторе.

Student* s = new Student(); 

while(theFile >> s->ID >> s->name >> s->surname >> s->points) 
{ 
    students.push_back(s); // here I would like to add this struct s from a file 
} 

Вы выделили только один ученик, и каждый раз, когда вы зацикливаете, вы читаете его снова и снова.

Вместо этого вы должны выделить нового ученика в каждом цикле и прочитать в новую выделенную память.

Student* s; 
int tmpId, tmpPoints; 
string tmpname, tmpsur; 

while(theFile >> tmpId >> tmpname >> tmpsur >> tmpPoints) 
{ 
    s = new Student(); 

    s->ID = tmpId ; 
    s->name = tmpname; 
    s->sur = tmpsur ; 
    s->points= tmpPoints; 

    studenti.push_back(s); // here You push a pointer to the newly allocated student 
} 
else 
{ 
    // There is error reading data 
} 

Не забудьте удалить каждого студента, когда вам больше не нужен вектор.

0

ваш код не работает, потому что у вас есть один объект Student и каждый раз перезаписывайте его элементы. Решение состоит в том, чтобы каждый раз создавать новый объект Student и передавать указатель на него на ваш вектор:

std::vector<Student*> students; 
int tmpId, tmpPoints; 
string tmpname, tmpsur; 

while(theFile >> tmpId >> tmpname >> tmpsur >> tmpPoints) 
{ 
    Student* s = new Student(); 
    s->ID = tmpId ; 
    s->name = tmpname; 
    s->sur = tmpsur ; 
    s->points= tmpPoints; 

    students.push_back(s); // push a pointer to new student object 
} 
else 
{ 
    // ... 
} 
Смежные вопросы