【问题标题】:How to pass a method to qsort?如何将方法传递给qsort?
【发布时间】:2024-10-12 05:00:02
【问题描述】:

有一个类包含一些数据,它会在某个时间点对它们进行排序。我使用qsort(),我想将比较函数作为一种方法保留在类中。问题是如何将方法传递给qsort(),以便编译器(g++)不会抛出任何警告?

尝试 1:

int Data::compare_records(void * rec_1, void * rec_2){
  // [...]
}

void Data::sort(){
  qsort(records, count, sizeof(*records), &Data::compare_records);
}

这种方式会产生错误:

error: cannot convert ‘int (Data::*)(const void*, const void*)’ to ‘int (*)(const void*, const void*)’ for argument ‘4’ to ‘void qsort(void*, size_t, size_t, int (*)(const void*, const void*))’

尝试 2:

void Data::sort(){
  qsort(
    records, count, sizeof(*records),
    (int (*)(const void*, const void*)) &Data::compare_records
  );
}

这种方式会产生警告:

warning: converting from ‘int (Data::*)(const void*, const void*)’ to ‘int (*)(const void*, const void*)’

那怎么做才是正确的呢?

【问题讨论】:

  • 你不应该在 C++ 中使用qsort。绝不。曾经。 std::sort 更快,更灵活和类型安全,qsort 不是这些。忘记 qsort 曾经存在过吧,至少除非你遇到需要使用纯 C 的环境。
  • 您应该使用std::sort 而不是C 函数qsort。该函数采用void * 参数这一事实破坏了编译器可以进行的大部分优化(conf H. Sutter)。
  • 事实上,如果Data 具有非平凡的复制构造函数或非平凡的析构函数,则使用qsort 是未定义的行为。它可以做任何事情,在记忆中呕吐是更令人愉快的可能性之一。

标签: c++


【解决方案1】:

如果您必须使用qsort 而不是std::sort推荐),将成员方法声明为static 就足够了。

【讨论】:

  • 我真的会让“(推荐)”更强大。 std::sort 更快,更灵活类型安全。
  • 而且更大(生成更多的二进制代码)。但如果你关心这一点,你可能一开始就没有使用 C++。
【解决方案2】:

您将函数传递为&Data::compare_records,但您应该将其传递为Data::compare_records,并将其设为static

【讨论】:

  • 两者在 C++ 中是等价的,而且迂腐地说,第一个版本实际上更能表达意图。
  • 谢谢,不知道。其实函数名已经是指向函数的指针了,这就是我记得的,也许这就是我忘记的原因,& 是不被禁止的
【解决方案3】:

不要在 C++ 中使用qsort。使用std::sortboost/std::bind。成员函数指针不能转换为函数指针。你的方法应该是static,或者应该是free function

请参阅Is the type of “pointer-to-member-function” different from “pointer-to-function”? 了解说明。

【讨论】:

    【解决方案4】:

    尽管我使用 Qt 的 qSort(),但对于 std::sort,此代码也可能会有所帮助

    函子可以很酷。

    struct randomWSort
    {
        SatoshiGame* This;
        randomWSort(SatoshiGame* g){This=g;}
        bool operator()(QString& a, QString& b)
        {
            return This->randomWSort(a,b);
        }
    };
    
    bool SatoshiGame::randomWSort(QString& a, QString& b)
    {
        return rand->rnd() %2;
    }
    
    QString SatoshiGame::getRandomString(QStringList words)
    {
        qSort(words.begin(), words.end(), ::randomWSort(this) );
        return words.at(0);
    }
    

    【讨论】: