【问题标题】:Why do I need to repeat the sorting subroutine when declaring a std::set?为什么在声明 std::set 时需要重复排序子程序?
【发布时间】:2013-08-25 18:03:15
【问题描述】:

在我的 C++ 程序中,我尝试按值而非键对地图进行排序。

this question 看来,这样做的方法似乎很清楚,即创建一个集合,其元素是对的,并且按我自己的小于函数排序。

这是我尝试执行此操作的一些示例代码:

#include <map>
#include <set>
#include <iostream>
#include <string>

using namespace std;

bool compareCounts(const pair<string, size_t> &lhs, const pair<string, size_t> &rhs);

int main (int argc, char *argv[]) {
        map <string, size_t> counter = { {"A", 1}, {"B", 2}, {"C", 3} };
        set <pair<string, size_t>, decltype(compareCounts) *> sorted_counter;
        for (map<string, size_t>::iterator it = counter.begin(); it != counter.end(); ++it) {
                cout << "About to add: " << it->first << ":" << it->second << endl;
                auto ret = sorted_counter.insert(*it);
                if (! ret.second) {
                        cout << "ERROR adding this element!" << endl;
                } else {
                        cout << "Element added ok" << endl;
                }
                cout << "Set is of size: " << sorted_counter.size() << endl;
        }

        return 0;
}

bool compareCounts(const pair<string, size_t> &lhs, const pair<string, size_t> &rhs) {
        return lhs.second > rhs.second;
}

这是输出:

即将添加:A:1
元素添加好了
套装尺寸:1
即将添加:B:2
分段错误:11

我注意到,当我添加第二个元素时,事情就崩溃了。我发现这种情况正在发生,因为现在需要调用我的排序子例程compareCounts

解决方法是更改​​此行:

set <pair<string, size_t>, decltype(compareCounts) *> sorted_counter;

到这里:

set <pair<string, size_t>, decltype(compareCounts) *> sorted_counter(compareCounts);

为什么我需要指定排序子程序compareCounts 两次?编译器不是已经从我的类型定义中知道了吗?

【问题讨论】:

  • 你在用什么,mapset?这很令人困惑。请举一个独立的例子
  • 我正在使用集合按值对地图进行排序。
  • 这是按需的事情还是两种结构的持续配对(我强烈建议不要这样做)?如果按需,您是否考虑过简单地将std::ref&lt;std::pair&lt;std::string,int&gt;&gt; 放入向量中并使用您自己的比较器触发std::sort()
  • 听起来像是标准的 C++ 陷阱。但是为什么插入使循环迭代器无效?迭代器在地图的元素之上。那不是保持不变吗?
  • 要回答您更新的问题,请参阅 Praetorians 答案(这是正确的答案)。您的 decl 告诉它比较器的 type (一个布尔返回函数,采用两个 const std::pair&lt;&gt; 引用),但您实际上从未 它一个要使用的比较器。在这种情况下我回退到使用仿函数的众多原因之一。

标签: c++ c++11 dictionary stl set


【解决方案1】:
set <pair<string, size_t>, decltype(compareCounts) *> sorted_counter;

您从未指定set 应该实际使用的比较器。将上面的行改为

set <pair<string, size_t>, decltype(compareCounts) *> sorted_counter(compareCounts);

如果没有指定比较器,set 默认构造一个 (nullptr),当它尝试使用比较器插入第二个元素时,您的代码会崩溃。

你应该只使用仿函数而不是函数指针

struct compareCounts
{
    bool operator()(const pair<string, size_t> &lhs, 
                    const pair<string, size_t> &rhs) const
    {
        return lhs.second > rhs.second;
    }
};

set <pair<string, size_t>, compareCounts> sorted_counter;

【讨论】:

  • 啊!我才意识到这是我的问题!
  • @User7391 即你告诉它比较器的type,但实际上从未它一个。
  • @User7391 注意在 Praetorians 的附加示例中,通过 operator() 告诉它可以(并且确实)使用该类型的实例进行 eval 的类型(函子)。它通常也是性能的首选,因为它很可能内联。如果我是你,我会使用他的仿函数示例。
  • 我以前没有听说过函子。我需要调查这些。
  • @David auto comp = [](...) {return ...;}; std::set&lt;foo, decltype(comp)&gt; s(comp); 怎么样? (我仍然更喜欢仿函数版本)
猜你喜欢
  • 1970-01-01
  • 2015-07-11
  • 2013-07-14
  • 1970-01-01
  • 1970-01-01
  • 2023-03-25
  • 1970-01-01
  • 1970-01-01
  • 2010-09-15
相关资源
最近更新 更多