【问题标题】:How do I Insert std::vector into a std::set which has a custom sort function如何将 std::vector 插入具有自定义排序功能的 std::set
【发布时间】:2018-12-12 19:24:59
【问题描述】:

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

我想将文件名的 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());

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

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

【问题讨论】:

  • 你调试过 DateOrderSorter 看看它是否运行良好?
  • 是的,我打印了这个集合并且能够验证它是否按日期顺序排序
  • 我的猜测是stat返回错误(代码没有检查),可能是因为path没有初始化到给定目录,而是默认初始化为""
  • 你能显示分配path的代码吗?
  • @Algorithmic 我不信,你能测试stat的返回值,来验证函数是否成功(即返回零)?

标签: c++ stl stdvector stdset


【解决方案1】:

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

这意味着比较函数对于 a &lt; ba &gt; b 都可以返回 true:这违反了 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 = "...";

【讨论】:

  • 其实你是对的。这是关于未初始化的路径变量。非常感谢!
  • 你介意我删除这个问题吗?对于只是试图将向量插入集合的人来说,这可能会产生很大的误导......
  • @Algorithmic 可能会更改标题。或者删除问题,如果你愿意,我不介意。
【解决方案2】:

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

【讨论】:

  • 我用touch File_name.txt 来保证时间不一样。所以我怀疑这个问题与文件名/日期是否相同。
猜你喜欢
  • 2014-08-10
  • 2013-02-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-18
  • 2019-05-07
  • 2018-05-31
  • 1970-01-01
相关资源
最近更新 更多