在 ostream 中使用迭代器失败

using iterator in ostream fails

我正在尝试实现 std::list 来替换此作业中的链表。我不允许更改声明,只能更改 .cpp 文件中的代码。在大多数情况下,我正在取得进步,但我在实施这个

时遇到了麻烦
std::ostream& operator<< (std::ostream& out, const Section& section);

即当我尝试创建一个迭代器时它失败了。我在代码的其他地方使用了迭代器,所以我不明白为什么它在这里失败了,我相信这是因为它是私有的,但我不确定如何在不更改明确禁止的 .h 文件的情况下解决问题:

std::ostream& operator<< (std::ostream& out, const Section& section)
{
  // 1. print the section header
  out << setw(8) << left << section.getCourse()
      << setw(6) << left << section.getCallNumber();
  out << ": " << section.getNumberOfStudents() << " students\n";

  // 2. collect the students, sort, and print
  Student* students = new Student[section.getNumberOfStudents()];
  {
    int i = 0;

    for ( auto pos = section.students.begin();
     pos != section.students.end(); pos++)
      {
    students[i] = pos;
    ++i;
      }
  }

  sort (students, students+section.getNumberOfStudents());

  for (int i = 0; i < section.getNumberOfStudents(); ++i)
    out << "    " << students[i] << "\n";

  out << flush;
  return out;
}
students[i] = pos;

应该改为

students[i] = *pos;

因为您想复制 Student 迭代器引用,而不是迭代器本身。

但是为什么动态数组是 Student 而不是 std::vector<Student>?目前你有内存泄漏,因为你没有 delete[] students;

编辑 1

已删除。

编辑 2

除此之外,我只能看出它错了

前面少了一个std::
sort (students, students+section.getNumberOfStudents());

这是假设没有使用自定义 sort 方法。

编辑 3

离开 rails 这里:

students[i] = *pos;

list 中的学生复制到动态数组 students 中。这可能很昂贵,所以这里有一个替代方案:

首先需要证明这一点的点点滴滴:必需包括

#include <iostream>
#include <list>
#include <vector>
#include <algorithm>
#include <functional>

最小学生class

class Student
{
    std::string name; 
public:
    Student(std::string inname):name(inname)
    {

    }
    const std::string & getname() const
    {
        return name;
    }
    friend bool operator<(const Student & a, const Student &b)
    {
        return a.name < b.name;
    }
};

一个最小的部分class

class Section
{
public:
    std::list<Student> students;
};

最小的外流运营商

std::ostream& operator<<(std::ostream& out, const Section& section)
{

一个std::vector而不是一个数组,和一个常量引用向量,这样我们就不必复制学生了。

    std::vector<std::reference_wrapper<const Student>> students;

vector 中存储引用。可能可以用 std::copystd::back_inserter 做一个衬里,但是对于一个例子来说,这有点太多了。

    for (const auto & student: section.students)
    {
        students.push_back(std::ref(student));
    }

排序vector

    std::sort(students.begin(), students.end());

打印vector

    for (const auto & student: students)
    {
        out << student.get().getname() << " ";
    }
    return out;
}

和一个 main 统治他们并在黑暗中束缚他们

int main()
{
    Section s;

    s.students.emplace_front("Tom");
    s.students.emplace_front("Dick");
    s.students.emplace_front("Harry");
    std::cout << s;
}

以及易于剪切和粘贴的多合一块:

#include <iostream>
#include <list>
#include <vector>
#include <algorithm>
#include <functional>

class Student
{
public:
    std::string name; // this is me being lazy. name should be private
    Student(std::string inname):name(inname)
    {

    }
    const std::string & getname() const
    {
        return name;
    }
    friend bool operator<(const Student & a, const Student &b)
    {
        return a.name < b.name;
    }
};

class Section
{
public:
    std::list<Student> students;
};

std::ostream& operator<<(std::ostream& out, const Section& section)
{
    std::vector<std::reference_wrapper<const Student>> students;

    // store references in the `vector`.
    for (const auto & student: section.students)
    {
        students.push_back(std::ref(student));
    }

     // Sort the `vector`
    std::sort(students.begin(), students.end());

    // print the `vector`
    for (const auto & student: students)
    {
        out << student.get().getname() << " ";
    }
    return out;
}

int main()
{
    Section s;

    s.students.emplace_front("Tom");
    s.students.emplace_front("Dick");
    s.students.emplace_front("Harry");
    std::cout << s;
}

或者按照 Remy 的建议,使用 std::vector<Student *> 和自定义比较器取消引用 std::sort 的指针。

正如其他人所说,错误是因为您在填充 students[] 数组时没有取消引用迭代器:

students[i] = pos; // <-- should be *pos instead!

我建议采用一种更快、更高效的替代方法:

std::ostream& operator<< (std::ostream& out, const Section& section)
{
  // 1. print the section header
  out << setw(8) << left << section.getCourse()
      << setw(6) << left << section.getCallNumber();
  out << ": " << section.getNumberOfStudents() << " students\n";

  // 2. collect the students, sort, and print
  std::vector<const Student*> students;
  students.reserve(section.getNumberOfStudents());

  for ( auto pos = section.students.cbegin();
    pos != section.students.cend(); ++pos)
  {
      students.push_back(&(*pos));
  }

  sort (students.begin(), students.end(), 
    [](const Student *a, const Student *b) { return (*a < *b); }
  );

  for ( auto pos = students.cbegin();
    pos != students.cend(); ++pos)
  {
    out << "    " << *(*pos) << "\n";
  }

  out << flush;
  return out;
}

感谢您的所有回答。最终成为一个更基本的问题。我必须将 Section 迭代器实现为 return 个学生迭代器。

    Section::iterator Section::begin() {
    return students.begin();
}

Section::const_iterator Section::begin() const {
    return students.begin();
}

Section::iterator Section::end() {
    return students.begin();
}

Section::const_iterator Section::end() const {
    return students.begin();
}