首页 > 解决方案 > 从 .txt 文件中读取并将它们存储到带有类对象的向量中作为 C++ 中的值

问题描述

    vector<Person*> people;
ifstream in_stream;
string line;
string name;
int age;

in_stream.open("people.txt");
getline(in_stream, line);
stringstream sline(line);
sline >> name >> age;
Person a(name, age);
people.push_back(&a);


for (auto x : people)
    cout << *x << endl;

所以我在这里有这段代码,我试图从这样形成的 .txt 文件中读取

Nick 23
Peter 27
Tom 42
Sofia 28
Daniel 39
Jonas 28

并将这些人(姓名和年龄)保存在一个向量中,该向量包含一个名为 Person 的类的指针。上面的代码工作正常,但是当我将 getline 放在一个 while 循环中时,我可以得到 txt 的所有行都在窃听,向量将是这样的

28
28
28
28
28
28

没有名字只是最后一个人的年龄。有什么想法我在这里做错了吗?人.h

#pragma once
#include <ostream>
#include <istream>
#include <iostream>
using namespace std;

class Person {
protected:
    string name;
    size_t age;
    virtual void print(ostream& out)  const;
public:
    Person(const Person& p);
    Person(string n, size_t a);
    Person();
    friend bool operator==(const Person& lhs, const Person& rhs);
    friend ostream& operator<<(ostream& out, const Person& rhs);
    friend istream& operator>>(istream& in, Person& rhs);

};

个人.cpp

#include "Person.h"

Person::Person(const Person& p) : name{p.name}, age {p.age}
{
}

Person::Person(string n, size_t a) : name{ n }, age{ a }
{
}

Person::Person() : name{"default"}, age {0}
{
}

bool operator==(const Person& lhs, const Person& rhs)
{
    if (lhs.name == rhs.name && lhs.age == rhs.age) {
        return true;
    }
    else {
        return false;
    }

}

void Person::print(ostream& out) const
{
    out << name << " " << age;
}

ostream& operator<<(ostream& out, const Person& rhs)
{
    rhs.print(out);
    return out;
}

istream& operator>>(istream& in, Person& rhs)
{
    string x;
    int y;
    in >> x >> y;
    rhs.name = x;
    rhs.age = y;
    return in;
}

非常感谢任何帮助。

标签: c++

解决方案


假设我们有

struct Person {
  std::string name;
  unsigned age;
};

我想老师希望你用 分配每个对象new,存储它的指针,然后再手动delete,但这只是因为老师教错了东西。你不应该写这样的新代码。按值保存事物(没有任何显式指针),或使用智能指针,如std::unique_ptr.

老师可能想要什么(或者,错误地认为他应该想要什么):

Person *addPerson(std::vector<Person*> &people, std::string &&name, int age)
{ 
  auto *person = new Person(std::move(name), age);
  people.push_back(person);
  return person;
}

// optional
void removePerson(Person *person, std::vector<Person*> &people)
{
  auto where = std::find(people.begin(), people.end(), person);
  if (where != people.end())
  {
    delete *where; // * dereferences the iterator, giving the pointer back
    std::erase(where);
  }
}

void removeAllPeople(std::vector<Person*> &people)
{
  for (auto *person : people)
    delete person;
  people.clear();
}

int main()
{
  std::vector<Person*> people;

  //... add people, modify people, etc

  removeAllPeople(); // free the memory
}

老师应该教的是什么:

// Hold people by value
std::vector<Person> people;

或者也许(即使没有必要)

// Hold people using owning pointers
std::vector<std::unique_ptr<Person>> people;

您可以做的是在读取文件生成指针向量,即

std::istream &operator>>(std::istream &is, Person &person)
{
  return is >> person.name >> person.age;
} 

std::ostream &operator<<(std::ostream &os, const Person &person)
{
  return os << person.name << ' ' << person.age << '\n';
}

std::vector<Person> readPeople(std::istream &from)
{
  std::vector<Person> people;
  Person person;

  while (from >> person) // while the read had succeeded
    people.push_back(std::move(person));

  return people;
}

std::vector<Person*> makePointersTo(std::vector<Person> &people)
{
  std::vector<Person*> pointers;
  pointers.reserve(people.size()); // since we know exactly how many items we need

  for (auto &person : people)
    pointers.push_back(&person);

  return pointers;
}

int main()
{
#if 1
  std::ifstream input;
  input.open("people.txt");
  if (!input.is_open()) abort();
#else
  // we could also be reading from standard input
  std::istream &input = std::cin;
#endif

  std::vector<Person> const peopleValues = readPeople(input);
  std::vector<const Person*> const people = makePointersTo(peopleValues);

  for (auto *person : people)
    std::cout << *person << '\n';

  // The memory will be freed by the vector destructors, automatically
}

没有必要重载比较运算符等 - 你不需要比较人,除非任务明确要求它。

而且:作业是如此之小(一百行左右)以至于要求将其分成多个文件是荒谬的。这是令人难以置信的荒谬。关注点分离是教学中非常重要的方面。如果您要引入流 I/O,则不应将其与如何将程序拆分为公开接口(.h文件)但在其他地方(.cpp文件)实现的逻辑模块混为一谈。事实上,你不应该鼓励任何人编写这样的小程序(<1000 行)被拆分成多个文件。总是适得其反。它没有任何帮助,只是添加样板,好像有一些样板神,你必须遵循他的牧师的建议,否则。


推荐阅读