Проблема с std :: stable_sort после обновления g ++ 9.1 - PullRequest
4 голосов
/ 26 июня 2019

После обновления с gcc / g ++ 8.1 до 9.1 и перекомпиляции моего кода большинство его тестов не прошло.Поэтому было сделано небольшое копание, и я обнаружил, что проблема была std::stable_sort.

Как выяснилось, большинство моих звонков на std::stable_sort были не нужны,то есть достаточно было бы позвонить std::sort.Таким образом, я произвел замену там, где это было возможно, и тесты, касающиеся этих фрагментов кода, снова прошли успешно.

Теперь у меня есть только один вызов std::stable_sort

void MshReader::determinePhysicalEntitiesRange() {
    // conns is not empty

    std::stable_sort(this->conns.begin(), this->conns.end(), 
        [=](const auto& a, const auto& b){
            return a[this->index] < b[this->index];
        }
    );

    // acess some values of conns
}

Где conns - это std::vector<std::vector<int>>, в котором хранятся соединения элементов.Сортировка выполняется на основе столбца index , его значение присваивается в заголовке класса, и все std::vector<int> в conns имеют эту запись.

Еще один факт заслуживает вниманияупомянуто, что в отладке сборках (используется флаг компилятора "-g", "-O3" НЕТ) все тесты завершаются успешно .

Также на release builds (используется флаг «-O3», «-g» - НЕ), печатая значения conns до и после вызова std::stable_sort, я обнаружил, что conns разрушен.

До

row:
  0:    0   2   0   1
  1:    0   2   1   2
  2:    0   1   2   5
  3:    0   1   5   8
  4:    0   3   8   7
  5:    0   3   7   6
  6:    0   0   6   3
  7:    0   0   3   0
  8:    1   4   3   4   9
  9:    1   4   3   9   6
 10:    1   4   4   7   9
 11:    1   4   6   9   7
 12:    1   4   1   2  10
 13:    1   4   1  10   4
 14:    1   4   2   5  10
 15:    1   4   4  10   5
 16:    2   4   4   5   8   7
 17:    2   4   0   1   4   3

После

row:
  0:    0   0   6   3
  1:    0   0   3   0
  2:    0   1   2   5
  3:    0   1   5   8
  4:    0   2   1   2 // there were two rows with column 'index' = 2
  5:    0   3   8   7
  6:    0   3   7   6
  7:    1   4   2   5  10  10  10  10 // this entry was previously on row 14; extra '10's
  8:    1   4   3   4   9
  9:    1   4   3   9   6
 10:    1   4   4   7   9
 11:    1   4   6   9   7
 12:    1   4   1   2  10
 13:    1   4   1  10   4
 14:    1   4   2   5  10
 15:    1   4   4  10   5
 16:    2   4   4   5   8   7
 17:    2   4   0   1   4   3

Вкл. Отладка сборок, std::stable_sort выходовожидаемый результат.Кроме того, используется c++17 (флаг компилятора "-std = c ++ 17").

Следовательно,

  • Что-то не так с моим вызовомstd::stable_sort?

  • Какие изменения в g ++ привели к такому поведению?

  • Почему это поведение появляется только в release builds?

Минимальный пример

#include <iostream>
#include <iomanip>
#include <vector>
#include <algorithm>

template<typename InputIt>
void print2D(InputIt cbegin, InputIt cend, std::string&& message) {
    std::cout << message;
    for (auto i = cbegin; i != cend; ++i) {
        for (auto j = i->cbegin(); j != i->cend(); ++j) {
            std::cout << "\t" << std::setw(3) << std::right << *j;
        }
        std::cout << std::endl;
    }
    std::cout << std::endl;
}

int main() {
    int index = 1;
    std::vector<std::vector<int>> conns{{0,2,0,1},{0,2,1,2},{0,1,2,5},{0,1,5,8},{0,3,8,7},{0,3,7,6},{0,0,6,3},{0,0,3,0},{1,4,3,4,9},{1,4,3,9,6},{1,4,4,7,9},{1,4,6,9,7},{1,4,1,2,10},{1,4,1,10,4},{1,4,2,5,10},{1,4,4,10,5},{2,4,4,5,8,7},{2,4,0,1,4,3}};

    print2D(conns.cbegin(), conns.cend(), "\n\n\tbefore\n");

    std::stable_sort(conns.begin(), conns.end(), 
        [=](const auto& a, const auto& b){
            return a[index] < b[index];
        }
    );

    print2D(conns.cbegin(), conns.cend(), "\n\n\tafter\n");

    return 0;
}

Если вышеуказанное скомпилировано с

    g++ -o main main.cpp -m64 -std=c++17 -O3

Выводится segmentation fault (core dumped).Однако, если флаг «-O3» не используется, ожидаемые результаты получаются.

1 Ответ

2 голосов
/ 26 июня 2019

Первый «b», который при компиляции с g ++ 9.1.1 передается в лямбду, имеет size()==0, что должно быть невозможно. clang ++ 8.0.0 запускает его без проблем с использованием тех же флагов компиляции и не показывает ничего странного при запуске valgrind.

Я бы сказал, что это ошибка в g ++. Код с отладочным выводом в лямбда-функции:

#include <algorithm>
#include <iomanip>
#include <iostream>
#include <vector>

template<typename InputIt>
void print2D(InputIt cbegin, InputIt cend, const std::string&& message) {
    std::cout << message;
    for(auto i = cbegin; i != cend; ++i) {
        for(auto j : *i) {
            std::cout << "\t" << std::setw(3) << std::right << j;
        }
        std::cout << "\n";
    }
    std::cout << "\n";
}

int main() {
    size_t index = 1;
    std::vector<std::vector<int>> conns{
        {0, 2, 0, 1},       {0, 2, 1, 2},      {0, 1, 2, 5},     {0, 1, 5, 8},
        {0, 3, 8, 7},       {0, 3, 7, 6},      {0, 0, 6, 3},     {0, 0, 3, 0},
        {1, 4, 3, 4, 9},    {1, 4, 3, 9, 6},   {1, 4, 4, 7, 9},  {1, 4, 6, 9, 7},
        {1, 4, 1, 2, 10},   {1, 4, 1, 10, 4},  {1, 4, 2, 5, 10}, {1, 4, 4, 10, 5},
        {2, 4, 4, 5, 8, 7}, {2, 4, 0, 1, 4, 3}};

    print2D(conns.cbegin(), conns.cend(), "\n\n\tbefore\n");

    std::stable_sort(conns.begin(), conns.end(), [=](const auto& a, const auto& b) {
        std::cout << index << "\ta.size=" << a.size() << " b.size=" << b.size() << "\n";
        return a[index] < b[index];
    });

    print2D(conns.cbegin(), conns.cend(), "\n\n\tafter\n");
}

Выход:

   before
     0    2     0   1
     0    2     1   2
     0    1     2   5
     0    1     5   8
     0    3     8   7
     0    3     7   6
     0    0     6   3
     0    0     3   0
     1    4     3   4    9
     1    4     3   9    6
     1    4     4   7    9
     1    4     6   9    7
     1    4     1   2   10
     1    4     1  10    4
     1    4     2   5   10
     1    4     4  10    5
     2    4     4   5    8      7
     2    4     0   1    4      3

1  a.size=4 b.size=0
Segmentation fault (core dumped)
...