如何将 std::vector 插入具有自定义排序功能的 std::set

How do I Insert std::vector into a std::set which has a custom sort function

注意这里的问题已经解决了,跟insert无关,而是一个未初始化的struct成员变量!希望这个问题及其答案可以帮助另一个菜鸟避免这样的错误。

我想将 std::vector 个文件名插入到 std::set 中,该 std::set 具有用于按日期而不是按字母顺序排序文件的客户排序器结构。

使用默认的字母顺序,我可以使用以下方法简单地将向量插入我的集合:

std::set<std::string> mySet;
std::vector<std::string> myVector;

myVector.push_back("Banana.txt");
myVector.push_back("Apple.txt");
myVector.push_back("Cat.txt");

mySet.insert(myVector.begin(), myVector.end());

这将完全符合我的期望:std::set 将按字母顺序排列的文件名。

现在,如果我有一个按日期而不是文件名排序的自定义排序器,就像这样:

struct DateOrderSorter
{
    bool operator()(const std::string& file1, const std::string& file2)
    {
        struct stat buf_stat1;
        struct stat buf_stat2;
        std::string fullpath1 = path + file1;
        std::string fullpath2 = path + file2;
        stat(&fullpath1[0], &buf_stat1);
        stat(&fullpath2[0], &buf_stat2);
        return buf_stat1.st_ctime < buf_stat2.st_ctime;
    }
    std::string path;
};

我声明我的集合为:

std::set<std::string, DateOrderSorter>

然后声明一个 DateOrderSorter 实例:

DateOrderSorter dateOrderSorter;
dateOrderSorter.path = "C:/random_path_that_has_been_verified_to_work"

当我做同样的插入时:

mySet.insert(myVector.begin(), myVector.end());

它returns 只是按日期排序的第一个和最后一个文件。所以只有 myVector.begin() 和 myVector.end().

  1. 首先,为什么会出现这种行为?
  2. 我该怎么做才能将向量插入到我的客户分类器订购的集合中。

我试过了

std::vector<std::string>::iterator vector_it = myVector.begin();
std::vector<std::string>::iterator vector_end = myVector.end();
for (; vector_it!= vector_end; ++vector_it) {
    mySet.insert(*vector_it);
}

但这并没有完全复制向量,而且顺序很奇怪。它没有遵循姓名或日期顺序..

因为ctime表示是Posix时间,即秒级。当然,两个不同的文件可能有相同的这次值,这实际上意味着文件状态发生变化的最后一次。尝试使用 std::mutiset.

比较函数的 path 成员默认初始化为“”,因此出现 stat 错误(该错误未被注意到,因为代码中未检查 return 值), buf_stat1.st_ctime < buf_stat2.st_ctime 正在比较未初始化的内存。

这意味着比较函数对于 a < ba > b 可以 return 为真:这违反了 strict weak ordering 的规则,因此您会观察到这种奇怪的行为。

要解决此问题,您可以使 path 成为静态成员,并验证 stat 没有错误,如下所示:

struct DateOrderSorter
{
    bool operator()(const std::string& file1, const std::string& file2)
    {
        struct stat buf_stat1;
        struct stat buf_stat2;
        std::string fullpath1 = path + file1;
        std::string fullpath2 = path + file2;
        int r = stat(&fullpath1[0], &buf_stat1);
        assert(r==0);
        r = stat(&fullpath2[0], &buf_stat2);
        assert(r==0);
        return buf_stat1.st_ctime < buf_stat2.st_ctime;
    }
    static std::string path;
};

并像这样初始化它:

DateOrderSorter::path = "...";