首页 > 解决方案 > 如何将 std::vector 插入具有自定义排序功能的 std::set

问题描述

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

我想将文件名的 std::vector 插入到具有客户排序器结构的 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());

它只返回按日期排序的第一个和最后一个文件。所以只有 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);
}

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

标签: c++stlstdvectorstdset

解决方案


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

这意味着比较函数可以为两者返回 true a < ba > b这违反了严格的弱排序规则,因此您会观察到这种奇怪的行为。

要解决此问题,您可以创建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 = "...";

推荐阅读