g++ 9.1 更新后 std::stable_sort 的问题
Problem with std::stable_sort after g++ 9.1 update
从 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列进行的,它的值赋值在class头,所有std::vector<int>
在conns 有那个条目。
另一个值得一提的事实是,在 调试 构建(使用编译器标志“-g”,“-O3”不是)所有测试成功.
此外,在 release 构建(使用标志“-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
在 debug 构建时,std::stable_sort
输出预期结果。除此之外,正在使用 c++17
(编译器标志“-std=c++17”)。
因此,
我打电话给 std::stable_sort
有问题吗?
g++ 的哪些更改导致了此行为?
为什么此行为仅出现在 release 版本中?
最小示例
#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”,则会获得预期的结果。
当使用 g++ 9.1.1 编译时,传递到 lambda 中的第一个“b
”具有 size()==0
,这应该是不可能的。 clang++ 8.0.0 使用相同的编译标志运行它没有问题,并且在 运行 valgrind
.
时没有显示任何奇怪的东西
我会说这是 g++ 中的错误。 lambda 函数中带有调试输出的代码:
#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)
从 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列进行的,它的值赋值在class头,所有std::vector<int>
在conns 有那个条目。
另一个值得一提的事实是,在 调试 构建(使用编译器标志“-g”,“-O3”不是)所有测试成功.
此外,在 release 构建(使用标志“-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
在 debug 构建时,std::stable_sort
输出预期结果。除此之外,正在使用 c++17
(编译器标志“-std=c++17”)。
因此,
我打电话给
std::stable_sort
有问题吗?g++ 的哪些更改导致了此行为?
为什么此行为仅出现在 release 版本中?
最小示例
#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”,则会获得预期的结果。
当使用 g++ 9.1.1 编译时,传递到 lambda 中的第一个“b
”具有 size()==0
,这应该是不可能的。 clang++ 8.0.0 使用相同的编译标志运行它没有问题,并且在 运行 valgrind
.
我会说这是 g++ 中的错误。 lambda 函数中带有调试输出的代码:
#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)