在循环中创建新对象时,将初始化未初始化的成员变量

时间:2015-08-31 10:01:22

标签: c++ file initialization

我正在编写一个从文件中读取行的程序。每行包含有关"学生"的数据。我要发布的所有代码可能看起来有点过分,但它确实是一个非常简单的程序,有一个非常具体的错误,所以我只是包含了所有这些,所以任何人都可以轻松地自己尝试。

我认为问题出在StudentList构造函数的while循环中。 创建了一个新的Student对象,即使id对象的成员变量gpaStudent未在其构造函数中初始化,它们似乎也被初始化为文件中前一行提供的值,即分配给在while语句的上一个循环中创建的对象的值。但这应该是不可能的,因为在每个循环之后对象被销毁。更多解释和代码如下:

头文件到Student

// Student.h

#pragma once
#include<string>
#include<sstream>

/*
   Class representing a student.
*/
class Student
{
public:
    Student(std::string studentInformation);
    std::string getFirstName();
    std::string getLastName();
    std::string getName();
    int getId();
    double getGPA();

private:
    std::string firstName;
    std::string lastName;
    int id;
    double gpa;

};

Student的源文件:

// Student.cpp
#include "Student.h"
#include<iostream>

using namespace std;

/*
    Purpose: Constructs a student.

    @param studentInformation Can contain first and last name, id and gpa score.
    All separated by whitespace.
*/
Student::Student(string studentInformation)
{
    // If no information about the student was provided:
    if (studentInformation.empty())
        cout << "THIS STUDENT IS EMPTY!" << endl;

    // Prints the object's id and gpa values. These should be uninitialized.
    cout << "current values gpa, id : " << id << ", " << gpa << endl;

    stringstream studentStream(studentInformation);
    cout << "chars in stream: " << studentStream.rdbuf()->in_avail() << endl;

    // Precaution just to check if there are any values to assign.
    if (!studentStream.rdbuf()->in_avail() == 0)
    {
        studentStream >> firstName;
        studentStream >> lastName;
        studentStream >> id;
        studentStream >> gpa;
    }
}


string Student::getFirstName()
{
    return firstName;
}

string Student::getLastName()
{
    return lastName;
}

string Student::getName()
{
    return firstName + " " + lastName;
}


int Student::getId()
{
    return id;
}

double Student::getGPA()
{
    return gpa;
}

头文件到StudentList

#pragma once

#include<string>
#include<vector>
#include<fstream>
#include<algorithm>

#include "Student.h"

class StudentList
{
public:
    StudentList(std::string filePath);

    Student getValedictorian();  // Not used here
    std::vector<Student> getHonorRollStudents();  // Not used here
    std::vector<Student> getFailingStudents();  // Not used here

//private:
    std::vector<Student> students;

};

源文件StudentList

#include "StudentList.h"
#include<iostream>

using namespace std;

/*
    Purpose: Initializes a member vector that holds elements of type Student.
    The values to initialize each element with are obtained from a .txt file.

    @param filePath The path to the file from which we should read the data from.
*/
StudentList::StudentList(string filePath)
{
    ifstream studentFile(filePath);

    string lineContents;  // Holds the content of each line in the file.
    int counter = 1;  // Counts the number of lines read.

    while (!studentFile.eof())
    {
        cout << "\nfile line counter: " << counter++ << endl;
        getline(studentFile, lineContents);
        cout << "current line content in file: " << lineContents << endl;

        // Create a new student from the lines content.
        // This object should not have any initialized data about name, id or gpa.
        Student s(lineContents);

        // Check what values were added to the object.
        cout << "name: " << s.getName() << " id: " << s.getId() << " gpa: " << s.getGPA() << endl;

        // Put the object in the vector
        students.push_back(s);
    }
    studentFile.close();

    // Sort the vector based on the gpa value, in descending order
    sort(students.begin(), students.end(), [](Student &s1, Student &s2)
                                           {
                                               return s1.getGPA() > s2.getGPA();
                                           });
}

我从以下网址读取数据的文本文件:

Shirley Temple 0235 93.8
John Appleseed 4325 89.2
Debbie Downer 9245 70.3

最后主要功能:

#include <iostream>

#include "Student.h"
#include "StudentList.h"

using namespace std;

// Practical method to write relevant info about a Student:
void printStudent(Student student)
{
    cout << "\nName: " << student.getName() << endl;
    cout << "ID: " << student.getId() << endl;
    cout << "GPA: " << student.getGPA() << endl;
}

int main() {

    // Create a new StudentList object that adds students to its vector,
    // based on the data obtained from the file:
    StudentList list("C:/Users/UserName/Documents/students.txt");

    // Check how many students were created and added to the vector in list.
    cout << "\n students vector length: " << list.students.size() << endl;

    for (Student s : list.students)
        printStudent(s);

    //Student s2("");
    //printStudent(s2);
    system("pause");
    return 0;
}

输出如下:

file line counter: 1
current line content in file: Shirley Temple 0235 93.8
current values gpa, id : -858993460, -9.25596e+61  // Not already initialized, which is expected.
chars in stream: 24
name: Shirley Temple id: 235 gpa: 93.8

file line counter: 2
current line content in file: John Appleseed 4325 89.2
current values gpa, id : 235, 93.8  // Already explicitly Initialized! How come!?
chars in stream: 24
name: John Appleseed id: 4325 gpa: 89.2

file line counter: 3
current line content in file: Debbie Downer 9245 70.3
current values gpa, id : 4325, 89.2  // Already explicitly Initialized! How come!?
chars in stream: 23
name: Debbie Downer id: 9245 gpa: 70.3

file line counter: 4
current line content in file:
THIS STUDENT IS EMPTY!
current values gpa, id : 9245, 70.3  // Already explicitly Initialized! How come!?
chars in stream: 0
name:   id: 9245 gpa: 70.3

file line counter: 5
current line content in file:
THIS STUDENT IS EMPTY!
current values gpa, id : 9245, 70.3  // Already explicitly Initialized! How come!?
chars in stream: 0
name:   id: 9245 gpa: 70.3

 students vector length: 5

Name: Shirley Temple
ID: 235
GPA: 93.8

Name: John Appleseed
ID: 4325
GPA: 89.2

Name: Debbie Downer
ID: 9245
GPA: 70.3

Name:
ID: 9245
GPA: 70.3

Name:
ID: 9245
GPA: 70.3
Press any key to continue . . .

所以我对于id构造函数中第一个读取行之后创建的每个gpa对象的StudentStudentList如何成为可能非常困惑,使用先前创建的对象的值初始化。 作为回顾,Student构造函数的开头如下所示:

Student::Student(string studentInformation)
    {
        // If no information about the student was provided:
        if (studentInformation.empty())
            cout << "THIS STUDENT IS EMPTY!" << endl;

        // Prints the object's id and gpa values. These should be uninitialized.
        cout << "current values gpa, id : " << id << ", " << gpa << endl;

据我所知,idgpa成员无法在cout语句之前显式初始化。然而,在StudentList构造函数中的第一个之后创建的所有对象在执行上面的cout时被初始化。怎么会这样?

1 个答案:

答案 0 :(得分:2)

如果内存未初始化,一切都可以在其中!

编译器似乎重用了旧临时变量的“旧”内存地址。

在ctor中初始化所有成员:

Student::Student(string studentInformation)
 :firstname(), lastname(), id(0), gpa(0)
{ 
... ctor stuff
}