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);          
        }
    }
6
  • 1
    I've got a better solution for your loop: ideone.com/hMgoP Commented Apr 2, 2012 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. Commented Apr 2, 2012 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. Commented Apr 2, 2012 at 17:14
  • 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. Commented Apr 2, 2012 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. Commented Apr 2, 2012 at 18:22

1 Answer 1

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().

Sign up to request clarification or add additional context in comments.

4 Comments

Additional note: if you want to reduce number of allocations, use students.reserve(initial_amount) (not resize).
You must make sure class grades has a proper copy constructor and assignment operator. That's a requirement for using a vector anyway.
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 - 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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.