3

Working on solving a simple problem in C++, want to understand how I could use vector of objects of user defined class type without fixed(worst case) number of elements allocated while instantiating that vector of objects. i.e.

Currently I have to use

vector<grades> students(10000); 

where 10000 is some max value of records I have assumed. if some file has more records, it crashes obviously.

So in case of code below, how to grow the vector of my class objects dynamically and read the records in my class variables. I cannot use push_back(), as explained in code below. Or how can i use push_back() ?

Code below should explain -

class grades
{
public:
    string mName;
    string mSurname;
    int mAge;
    string mLocation;
    int mMarks;
    char mGrade;

    //void readdata();
    void calcgrade();
    void showgrade(string name_surname);

};

    using namespace std;
    int main(int argc,char *argv[])
    {
        **vector<grades> students(10000);// I do not want to do this but make it dynamic**
        ifstream infile;
        char c;
        int i=0;
        int no_of_records=0;

        infile.open(argv[1],ios::in);
        if(infile.is_open() != true)
        {
            cerr << "Error opening input data file:" <<argv[1] << "...exiting\n";
            exit(-1);
        }

            while(!infile.eof()) 
            {
                 infile >> students[i].mName;//Can i use push_back() here and for reading all below entities, to make vector grow dynamically
                infile >> students[i].mSurname;
                infile >> students[i].mAge;
                infile >> students[i].mLocation;
                infile >> students[i].mMarks;
                i++;
                no_of_records++;
            }

            for(i=0;i<no_of_records;i++)
            {
               //Do some functions on each object students[i] in the vector 
            }
}

FYI:- I read a text file in C++ which has entries as below(The order of entities and number of different types of entities in one row is fixed which I know but the number of rows can vary based on different input file to be read) :

Name1 Surname1 Course1 Marks1
Name2 Surname2 Course2 Marks2
Name3 Surname3 Course3 Marks3
...
...

EDIT: code to handle all kinds of spurious spaces, tabs in records entities

while(!infile.eof()) 
    {
        c=infile.get();     
        if(isalnum(c))
        {
            infile.seekg(-1,ios::cur);
        }

        if(isalnum(c))
        {
            grades stud_temp;

            infile >> stud_temp.mName;
            infile >> stud_temp.mSurname;
            infile >> stud_temp.mAge;
            infile >> stud_temp.mLocation;
            infile >> stud_temp.mMarks;         
            students.push_back(stud_temp);          
        }
    }
goldenmean
  • 18,376
  • 54
  • 154
  • 211
  • 1
    I've got a better solution for your loop: http://ideone.com/hMgoP – Benjamin Lindley Apr 02 '12 at 16:49
  • @BenjaminLindley - Thats super. It works but I could not understand the logic. I tried to debug but could not get the logic. In your for() which part of code is the test-expression, which is the increment operation. How does it handle the space at the beginning of each record itself or empty lines in between and at end. – goldenmean Apr 02 '12 at 17:06
  • The test expression is the part that reads all the data in: `inFile >> temp.mName >> temp.mAge etc...` -- It relies on two basic facts. 1) istream operator>> returns the stream. 2) streams can be tested for validity in a boolean context. So it tries to read the data in, and if it fails(because of eof or something else), then the condition is false. If the read succeeds then the condition is true. -- There is no increment operation. It handles the extra space by simply relying on the operator's normal treatment of whitespace, which is to just skip over it. – Benjamin Lindley Apr 02 '12 at 17:14
  • But then when i had similar simple solution of while(!infile.eof())... if the text file had some extra spaces on last line or extra blank lines containing spaces, it was adding one repeated entry for last record from the file. Why was that? I thought the extraction operator >> should have handled the extra spaced at end. Just trying to understand how does this logic of yours does that? – goldenmean Apr 02 '12 at 18:12
  • 1
    `operator>>` starts by looking for the next element, skipping over whitespace. Then when it's reading the element, it stops at the first whitespace it finds. With the "check for eof" version, after you've read the last element, if there are still spaces left in the file, then eof has not been reached, so you enter the loop again, trying to read an element (which fails), but you still store the element in the vector. – Benjamin Lindley Apr 02 '12 at 18:21
  • 1
    Whereas, with my version, since the success of the read determines whether or not we will even enter the loop, a failed read means we don't even enter the loop, so the element does not get put into the vector. – Benjamin Lindley Apr 02 '12 at 18:22

1 Answers1

8

You can just declare your vector first:

vector<grades> students;

And then read the values, while pushing elements in the vector:

while(!infile.eof()) 
{
    grades student;
    infile >> student.mName;
    infile >> student.mSurname;
    infile >> student.mAge;
    infile >> student.mLocation;
    infile >> student.mMarks;
    students.push_back(student);
}

You don't need no_of_records anymore, since the number of records will be students.size().

Luchian Grigore
  • 253,575
  • 64
  • 457
  • 625
  • 1
    Additional note: if you want to reduce number of allocations, use `students.reserve(initial_amount)` (not `resize`). – Cat Plus Plus Apr 02 '12 at 16:17
  • 1
    You must make sure class `grades` has a proper copy constructor and assignment operator. That's a requirement for using a `vector` anyway. – Mark Ransom Apr 02 '12 at 16:23
  • If there's a single extra space or new line at the end of the file(which should certainly be allowed for text files), your code adds an additional uninitialized element to the vector. – Benjamin Lindley Apr 02 '12 at 16:30
  • @Benjamin - I know. In fact I have handled many cases of spurious spaces(vertical-tab,horizontal tabs,space,newline etc...) in my actual code. Pls. See the edited code if interested. – goldenmean Apr 02 '12 at 16:36