如何遍历集合C++的所有元素

How to iterate through all elements of set C++

本文关键字:C++ 元素 集合 何遍历 遍历      更新时间:2023-10-16

[更新:我的问题解决了!非常感谢Mike Seymour和Niall以及你们所有人!]

我的代码在for循环中有错误,我不知道如何修复它:(

MyClass::ITECH7603Class(set<Student>* students) {
    /* Initialize dynamically the group field */
    group = new map<string, Student>();
    for (set<Student>::iterator it = students->begin(); it != students->end(); it++) {
        addStudent(it);
    }
}
void MyClass::addStudent(Student* studentPtr) {
    string fullName = studentPtr->getName() + " " + studentPtr->getSurname();
    group->insert(pair<string, Student>(fullName, *studentPtr));
}

因此,主要的想法是循环浏览集合中的所有学生,并将每个学生添加到一个地图组中。有什么帮助吗?非常感谢!

for (set<Student>::iterator it = students->begin; it != students->end; it++) {
    addStudent(it);
}

应该是:

for (set<Student>::iterator it = students->begin(); it != students->end(); it++) {
                                               //^^                   //^^
    addStudent(it);
}

addStudent采用指针,而it是迭代器,因此不能直接传递。

您应该更改addStudent以获取值或指向const:的指针/引用

// option 1
void addStudent(Student);
addStudent(*it);
// option 2
void addStudent(Student const &);
addStudent(*it);
// option 3
void addStudent(Student const *);
addStudent(&*it);

如果,正如你在评论中所说,你必须让它使用一个可变指针,那么你需要一些奇怪的查询来处理集合元素是不可变的这一事实:

// nasty option
addStudent(const_cast<Student*>(&*it));
// slightly less nasty option
Student copy = *it;
addStudent(&copy);

注意,如果函数使用不可靠的指针对存储在集合中的Student对象进行任何修改,则第一个选项将给出未定义的行为。第二个生成临时副本,可以在不破坏集合的情况下对其进行修改。只要addStudent只存储传递给它的对象的副本,而不是指针本身,这是可以的,当copy被销毁时,指针本身将变为无效。

在c++11中,您可以使用sytax:的范围

for (const auto &student : *students)
{
    addStudent(it);
}

然后更改addStudent函数签名以接受引用:

void MyClass::addStudent(const Student &student) {

虽然您得到的答案可以"修复"您的代码,使其达到编译和生成您显然可以接受的结果的程度,但就代码风格而言,我觉得它们不是很令人满意。我会以完全不同的方式来做这项工作。特别是,我的代码不会有一个(显式)循环。如果我需要大致按照你的要求做,我可能会使用这样的代码:

std::pair<std::string, Student> make_mappable(Student &stud) { 
    return std::make_pair(stud.getName() + " " + stud.getSurName(), stud);
}
std::map<std::string, Student> gen_map(std::set<Student> const &input) { 
    std::map<std::string, Student> ret;
    std::transform(input.begin(), input.end(), 
                   std::inserter(ret, ret.end()), 
                   make_mappable);
    return ret;
}

肯定看不到任何new,也不会有任何指向Student的指针。

OTOH,由于你用作map密钥的数据是集合中项目中已经存在的数据,因此继续使用集合可能更方便,只需根据学生的姓名指定一个比较函数:

struct by_given_name {
    bool operator()(Student const &a, Student const &b) const { 
        if (a.getName() < b.getName())
            return true;
        if (b.getName() < a.getName())
            return false;
        return a.getSurName() < b.getSurName();
    }
};
std::set<Student, by_given_name> xform(std::set<Student> const &in) { 
    return std::set<Student, by_given_name>{in.begin(), in.end()};
}

就其价值而言,后者的现场演示。

后者是否实用通常取决于另一个因素:您仅凭姓名创建Student的能力。如果你不能做到这一点,按名字搜索会很不方便(充其量),所以你想使用地图。

我意识到,这可能对一个班的家庭作业没有多大帮助(如果有的话),但即使你的班阻止你真正打开像样的代码,对我来说,至少值得尝试学习除了它需要的东西之外,还写体面的代码。如果你通过了这门课,找到了一份编写代码的工作,你可能宁愿你的同事不想伤害你。