插入数据后,C ++映射为空。

时间:2019-01-03 13:14:18

标签: c++

首先,祝遇到我问题的人们新年快乐。

我目前正在学习C ++,并且有一个课堂项目要完成。

简而言之,我的代码(到目前为止)应该实例化具有从txt文件(名称,注册号和的映射)中读取的详细信息的学生对象,并将该学生添加到列表中。 然后,我阅读了第二个txt文件(由注册号,课程代码和标记组成),并检查读取的内容和列表之间是否存在学生注册号的匹配。 如果匹配,我应该将从txt文件中读取的分数插入地图(学生对象的一部分)中,这样以后,每个学生都有一张地图,其中包含所修课程和取得的分数 我似乎可以很好地创建列表,然后使用stringstream读取第二个文件并遍历该列表以比较reg-number。 如果有匹配项,则调用add mark方法将标记添加到地图。 就是这样。如果在我完成地图插入之后,我循环并打印学生的地图,则该地图为空。对于所有学生。为了确认这一点,我使用了map.size()。 我已经尝试了多种方法来理解和纠正此问题,但似乎我漏掉了某些要点。本能告诉我,添加标记方法正在将引用复制到传递的变量中,然后在main方法中由字符串流销毁该引用,因此在映射中未显示任何数据。不幸的是,我不能更改头文件中的任何代码,只能实现声明的内容。 在阅读了std库文档中的字符串,映射等信息,并尝试了多种纠正行为的方法之后,我很茫然。 任何建议将不胜感激,因此我可以继续进行该项目并更好地了解正在发生的事情。我已经在下面添加了文件。还有一个Person基类,但是我没有更改它,因为它仅包含一个setter和getter。 预先非常感谢。

学生标题:

#ifndef _STUDENT_H_
#define _STUDENT_H_

#include <string>
#include <map>
#include <stdexcept>
#include "Person.h"

using namespace std;

class NoMarkException: public exception
{
};

class Student: public Person
{   public:
        // constructor should initialise name and registration number using arguments
        // and initialise marks map to be empty
        Student(const string &name, int regNo);

       // method to return registration number
       int getRegNo() const;

       // method to add the mark to the map
       // if a mark for the module is already present it should be overwritten
       void addMark(const string& module, float mark);

       // method to retrieve the mark for a module
       // should throw NoMarkException if student has no mark for that module
       float getMark(const string &module) const throw (NoMarkException);



    private:
       int regNo;
       map<string, float> marks;  // keys are modules, values are marks in range 0.0 to 100.0

    // friend function to output details of student to stream
    // should output name, regno, and minimum, maximum and average marks on a single line
    // if the student has no marks "has no marks" should be output instead of the marks
    friend ostream& operator<<(ostream &str, const Student &s);
};

#endif

Student.cpp文件:

#include <iostream>
#include "Student.h"
#include "Person.h"

using namespace std;


//constructor makes a student object and initialises the map; marks.
Student::Student(const string &name, int regNo) : Person(name) {
    this->name = name;
    this->regNo = regNo;
    map<string, float> marks;
}

//implemented from the header file. Returns the registration number.
int Student::getRegNo() const {
    return regNo;
    }


// implemented as per header file request. adds marks to the map. if a mark exists, then it is overwritten.
void Student::addMark(const string &module, float mark) {
    marks[module] = mark;
    cout << "added: " << marks[module]<< endl;
}

//used to find marks in a map.
float Student::getMark(const string &module) const throw (NoMarkException) {
    auto search = marks.find(module);
    //line to test the map size after using addMark.
    cout << "size after inputted values: "<< marks.size();
    return marks[module];
}

main.cpp文件

#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
#include <list>
#include "Student.h"

using namespace std;

//main method to obtain a file name from a user and read the file.
//method passes each .. to student.cpp
int main() {
    //setting up variables required
    string fileName;
    const string fileEnd = ".txt";
    string line;
    string line2;
    ifstream file;
    int reg;
    int reg2;
    string studName;
    string lastName;
    float mark;
    string module;
    list<Student> listOfStudents;

    cout << "Please enter a file name to access..." << std::endl;
    cin >> fileName;
    fileName += fileEnd;

    // opening file an reading its contents. values are prepared and sent to the Student constructor. Fills a list
    // with student objects created with variables read from the studs.txt file.
    //checks file is found and exits the program if not
    file.open(fileName);
    if (!file) {
        cerr << "Unable to open file " << fileName << endl;
        exit(1);
    }
    while (getline (file, line)) {
        stringstream stream (line);
        stream >> reg >> studName >> lastName;
        studName += (' ' + lastName);
        cout << "Student:  " << studName << " has been created." << endl;
        listOfStudents.push_front(Student(studName, reg));
    }
    file.close();
    cout << "The list of students has been created :)" << endl << endl;
    cout << "Please enter the name of the next file to open"<< endl;
    cout << listOfStudents.size()<<endl;

// opening second file. If file not found, exit with an error code.
// otherwise read each line, separate the three words into variables, then loop through the previously created list 
//and look for a match of regNo. if true then call the addMark method to add the module and mark to the student's map.
    cin >> fileName;
    fileName += fileEnd;
    file.open(fileName);
    if (!file) {
        cerr << "Unable to open file " << fileName << endl;
        exit(1);
    }

    while(getline(file, line))
    {
        istringstream line_stream(line);
        line_stream >> reg2 >> module >> mark;

        for(Student stud : listOfStudents){
            if(stud.getRegNo() == reg2){//out << "Match reg2: " << reg2 << " with stud: " << stud.getName() <<stud.getRegNo()<< endl;
            stud.addMark(module,mark); }

        }
    }
    //testing the get mark method of student class. with a module that is in the map. expecting a result
    for(Student s :listOfStudents){
        cout << s.getMark("CE151") << endl;
    }

    return 0;
}

2 个答案:

答案 0 :(得分:6)

每次要添加Mark时,您都会创建一个Student的临时副本,然后将其丢弃。您无需复制它,而是使用引用,如下所示:

for (auto& stud: listOfStudents) /* stud.addMark */

打印结果时避免复制学生也是一个好主意:

for (const auto& stud: listOfStudents) /* stud.getMark */

Aaa和另外一件事:

float getMark(const string &module) const throw (NoMarkException);

动态异常规范在C ++ 11中已弃用,在更高版本的标准中已删除。认为这是一种不好的做法,应该避免。

答案 1 :(得分:1)

用户的答案:grungegurunge几乎就是您要寻找的答案。但是,看完你的课后。我注意到在私有部分的成员变量中,您已经声明了map<string, float> marks,这是可以的。但是,当我在设置nameregNo之后查看您的类的构造函数时,您似乎在声明另一个名为map<string, float>的{​​{1}},其中该变量仅在构造函数本地什么也没做。您在具有自动存储功能的堆栈上创建本地内存,从不使用它,然后在对象超出范围后被销毁;不必在这里声明它。

marks