我正在编写一个从文件中读取行的程序。每行包含有关"学生"的数据。我要发布的所有代码可能看起来有点过分,但它确实是一个非常简单的程序,有一个非常具体的错误,所以我只是包含了所有这些,所以任何人都可以轻松地自己尝试。
我认为问题出在StudentList
构造函数的while循环中。
创建了一个新的Student
对象,即使id
对象的成员变量gpa
和Student
未在其构造函数中初始化,它们似乎也被初始化为文件中前一行提供的值,即分配给在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
对象的Student
和StudentList
如何成为可能非常困惑,使用先前创建的对象的值初始化。
作为回顾,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;
据我所知,id
和gpa
成员无法在cout
语句之前显式初始化。然而,在StudentList
构造函数中的第一个之后创建的所有对象在执行上面的cout
时被初始化。怎么会这样?
答案 0 :(得分:2)
如果内存未初始化,一切都可以在其中!
编译器似乎重用了旧临时变量的“旧”内存地址。
在ctor中初始化所有成员:
Student::Student(string studentInformation)
:firstname(), lastname(), id(0), gpa(0)
{
... ctor stuff
}