【问题标题】:How to tell std::set to 'refresh' its ordering?如何告诉 std::set '刷新'它的排序?
【发布时间】:2009-06-20 09:57:09
【问题描述】:

如果集合中元素的值发生变化,则排序可能不再正确。如这个小程序所示:

#include <algorithm>
#include <iostream>
#include <set>
#include <string>

struct Comp
{
    bool operator()(const std::string * lhs, const std::string * rhs)
    {
        return *lhs < *rhs;
    }
};

int main()
{
    typedef std::set<std::string*, Comp> MySet;
    MySet mySet;

    std::string * a = new std::string("a");
    mySet.insert(a);

    std::string * c = new std::string("c");
    mySet.insert(c);

    std::string * b = new std::string("b");
    mySet.insert(b);

    for (MySet::iterator it = mySet.begin(); it != mySet.end(); ++it)
    {
        std::cout << *(*it) << std::endl;
    }

    // Ouput has correct order:
    // a
    // b
    // c


    *b = "z";
    std::cout << std::endl;

    std::string * d = new std::string("d");
    mySet.insert(d);    

    for (MySet::iterator it = mySet.begin(); it != mySet.end(); ++it)
    {
        std::cout << *(*it) << std::endl;
    }

    // Output no longer ordered correctly:
    // a
    // d
    // z
    // c

    return 0;
}

如何告诉集合“刷新”其内部排序?

【问题讨论】:

  • 值应该改变。 value_type 应该是 std::set&lt;const std:string*&gt; (虽然我相信 VS 不遵守那个?)
  • 值类型是用户传递的,加上一个顶级的const。如果用户传递std::string*,则值类型将为std::string* const。没有规则禁止用户传递不强制值排序位置不变性的东西;只有一条规则说以这种方式修改值会产生未定义的行为。

标签: c++ stl


【解决方案1】:

这里的主题非常相似(虽然不是完全重复,因为您使用自定义比较存储指向可变对象的指针):

what happens when you modify an element of an std::set?

基本上,不要做你想做的事。相反,当您要修改 set 持有指针的对象时,请先删除指针,然后修改对象,然后重新插入指针。

【讨论】:

    【解决方案2】:

    简单地说,你不能。如果您将一个项目放入一个集合中,则不应以改变其顺序的方式更改该项目。如果您需要以这种方式更改项目,则需要将其从集合中移除 (set::erase),然后重新插入具有新值的新项目 (std::insert)。

    【讨论】:

      【解决方案3】:

      如果集合中元素的值发生变化

      停止!这不可能合法地发生。

      std::set 不提供任何方式来满足您的要求,因为它已经是永远不需要手动重新订购的先决条件。

      【讨论】:

        【解决方案4】:

        值得指出的是,如果您使用的是 vs 2008,std::set 实现支持非常量迭代器,使您描述的代码可以使用该库成功编译。在其他 stl 实现中(例如 sgi's),set::const_iteratorset::iterator 属于同一类型,它们会抱怨显式设置新键值。

        【讨论】:

        • Set 迭代器在标准中是 const 的。如果您尝试通过迭代器更新集合的成员,您应该得到编译错误。
        【解决方案5】:

        使用不同的比较谓词将其复制到自身中。

        std::set MySet();
        
        /* add entries*/
        
        MySet = std::set(MySet.begin(), MySet.end(), Comp);
        

        通常这用于指定不同的比较操作,例如使用存储的类/结构的不同部分对其进行排序。

        【讨论】:

        • 注意。这将比删除单个项目、修改它然后重新添加要昂贵得多。
        • 如果这会导致 MySet 发生变化,那已经是未定义的行为
        • std::set&lt;...&gt; MySet();不是变量..这是一个函数声明!!
        猜你喜欢
        • 1970-01-01
        • 2012-01-05
        • 1970-01-01
        • 1970-01-01
        • 2014-06-14
        • 1970-01-01
        • 2020-03-18
        • 1970-01-01
        • 2011-11-12
        相关资源
        最近更新 更多