Как вставить std :: vector в std :: set, в котором есть пользовательская функция сортировки - PullRequest
0 голосов
/ 04 июля 2018

Обратите внимание, что проблема здесь решена, и она не имеет ничего общего со вставкой, а является неинициализированной переменной члена структуры! Надеюсь, этот вопрос и его ответ могут помочь другому новичку избежать такой ошибки.

Я хочу вставить 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 :: набор имен файлов, которые будут упорядочены в алфавитном порядке.

Теперь, если у меня есть собственный сортировщик, который сортирует по дате, а не по имени файла, вот так:

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

Но это не копировало вектор полностью, и порядок был очень странным. Это не следовало за именем или датой заказа ..

Ответы [ 2 ]

0 голосов
/ 04 июля 2018

Элемент path функции сравнения по умолчанию инициализируется как "", следовательно, stat ошибки (ошибка остается незамеченной, поскольку возвращаемое значение не проверяется в коде), а buf_stat1.st_ctime < buf_stat2.st_ctime сравнивает неинициализированную память .

Это означает, что функция сравнения может возвращать true для a < b и a > 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 = "...";
0 голосов
/ 04 июля 2018

Поскольку ctime предполагает, что это время Посикса, то есть вторая шкала. Конечно, два разных файла могут иметь одно и то же значение этого времени, что фактически означает, что в последний раз статус файла изменялся. Попробуйте использовать std::mutiset.

...