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

标签 c++ stl stdvector stdset

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

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

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

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::文件名。

现在,如果我有一个按日期而不是文件名排序的自定义排序器,如下所示:

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. 我该怎么做才能通过我的客户分类器将 vector 插入到我的集合中。

我试过了

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);
}

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

最佳答案

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

这意味着比较函数可以为 a < b 返回 true和 a > b : 这违反了 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 = "...";

关于c++ - 如何将 std::vector 插入具有自定义排序功能的 std::set,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51172214/

相关文章:

c++ - 树的直径

c++ - 如何有效地将 std::sort 与不透明数据类型一起使用?

c++ - rcpp包创建符号找不到错误

c# - 在 C++ 中部署 GBM 模型 |让 Predict.gbm 在 R 之外工作

c++ - 计算 std::set 中低于给定值的元素

c++ - 在不复制的情况下构造一个范围内的 vector

c++ - 从 std::vector 删除范围 vector 的最佳方法

c++ - 复制算法与容器构造函数

c++ - 无法使用 Visual Studio 2010 编译 QT 4.7.3

c++ - 调整 STL vector 的大小是否会删除/使其以前的内容无效?