访问算法的 lambda 函数中的迭代器导致我出现分段错误
Posted
技术标签:
【中文标题】访问算法的 lambda 函数中的迭代器导致我出现分段错误【英文标题】:access to iterator in lambda function of an algorithm cause me segmentation fault 【发布时间】:2020-02-28 14:30:52 【问题描述】:我需要按列对表格进行排序。我的表格由单个向量表示。
示例:
col_name A B C
向量:1 2 3 6 5 4 7 8 9
给我桌子:
A B C
1 6 7
2 5 8
3 4 9
对 B 列进行排序后,我需要获得:
A B C
3 4 9
2 5 8
1 6 7
我的代码:
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
int main()
std::vector<std::string> vec = "1","8","1","2","3","2","3",
"5","5","2","5","6","5","6",
"9","3","3","4","8","3","9";
std::vector<std::string> rec = "1","1","8","2","2","3","3",
"2","5","5","5","5","6","6",
"3","9","3","4","3","8","9";
int size = 7;
int col_idx = 1;
for(int i = 0; i<3;++i)
if(i==col_idx)
continue;
std::sort(vec.begin() + i*size, vec.begin() + (i+1)*size,
[col_idx, size, i](std::string& s1,std::string& s2)
std::cout << s1 << " "
<< s2 << " "
<< *(&s1 +(col_idx - i)*size) << " "
<< *(&s2 +(col_idx - i)*size) << " "
<< (*(&s1 +(col_idx - i)*size) < *(&s2 +(col_idx - i)*size)) << std::endl;
return *(&s1 +(col_idx - i)*size) < *(&s2 +(col_idx - i)*size);
);
std::sort(vec.begin() + col_idx*size, vec.begin() + (col_idx+1)*size);
assert(vec==res);
我有一个分段错误错误:cout 中只出现第一行。
【问题讨论】:
有什么理由不简单地使用std::vector<std::vector<int> >
?
使用调试器!
如果您的 std::sort
谓词对于概念上简单的事物(对列进行排序)看起来令人费解,那么请退后一步并重新考虑您的方法(您如何构建数据、选择的数据类型等.)
这是一个示例代码。在实际代码中,这允许一些理论上的加速,并且我无法更改整个代码中的所有方法。
能否请您在代码中包含数字的实际输出和预期输出?
【参考方案1】:
老实说,你的方法在我看来相当复杂。它的大部分复杂性是由于您的代码中有行但它们仅隐式存在。使代码中的内容显式不仅有助于提高可读性,而且使代码更容易编写。
假设您对行使用std::array<std::string,3>
,那么您的代码可以像这样轻量级:
#include <vector>
#include <array>
#include <algorithm>
#include <iostream>
int main()
using row_t = std::array<std::string,3>;
std::vector<row_t> vec = "1","8","1","2","3","2","3","5","5","2","5","6";
std::sort(vec.begin(),vec.end(),[](const row_t& a, const row_t& b) return a[2] < b[2]; );
for (const auto& row : vec)
for (const auto& e : row) std::cout << e << " ";
std::cout << '\n';
输出:
1 8 1
2 3 2
3 5 5
2 5 6
好吧,这可能是解决这个问题的好方法,也许这是我应该做的,但我不能通过 2 个月来更改所有代码......
您可以在问题中更清楚地说明要求。我认为,如果您有 10k 行代码依赖于使用平面向量的这个特定问题,那么当不同的数据结构更合适时,那么您将面临比如何对行进行排序更大的问题。总之……
使用平面std::vector
通常不是一个坏主意。我从你的代码中错过的是
template <int stride>
std::string& access_at(std::vector<std::string>& vec,size_t row,size_t col)
return vec[ row * stride + col ];
template <int stride>
const std::string& access_at(const std::vector<std::string>& vec,size_t row,size_t col)
return vec[ row * stride + col ];
这让您可以像这样迭代表:
for (size_t i=0;i < vec.size()/3;++i)
for (size_t j=0;j<3;++j)
std::cout << access_at<3>(vec,i,j) << " ";
std::cout << '\n';
接下来我将无耻地窃取和修改this answer的代码。基本思想是对索引向量进行排序,而不是直接对向量进行排序:
using index_t = std::vector<size_t>;
template <int stride>
index_t make_sorted_index(const std::vector<std::string>& values,size_t col)
index_t index(values.size() / stride);
std::iota(index.begin(), index.end(), 0);
std::sort(index.begin(),
index.end(),
[&values,&col](size_t a, size_t b)
return access_at<stride>(values,a,col) < access_at<stride>(values,b,col);
);
return index;
一旦你有了这个,打印排序表的循环只需要一个小的修改:
for (size_t i=0;i < vec.size()/3;++i)
for (size_t j=0;j<3;++j)
std::cout << access_at<3>(vec,index[i],j) << " ";
std::cout << '\n';
把所有东西放在一起:
#include <vector>
#include <numeric>
#include <algorithm>
#include <iostream>
template <int stride>
std::string& access_at(std::vector<std::string>& vec,size_t row,size_t col) return vec[ row * stride + col ];
template <int stride>
const std::string& access_at(const std::vector<std::string>& vec,size_t row,size_t col) return vec[ row * stride + col ];
using index_t = std::vector<size_t>;
template <int stride>
index_t make_sorted_index(const std::vector<std::string>& values,size_t col)
index_t index(values.size() / stride);
std::iota(index.begin(), index.end(), 0);
std::sort(index.begin(),
index.end(),
[&values,&col](size_t a, size_t b) return access_at<stride>(values,a,col) < access_at<stride>(values,b,col);
);
return index;
int main()
std::vector<std::string> vec = "1","8","1","2","3","2","3","5","5","2","5","6";
for (size_t i=0;i < vec.size()/3;++i)
for (size_t j=0;j<3;++j)
std::cout << access_at<3>(vec,i,j) << " ";
std::cout << '\n';
std::cout << '\n';
auto index = make_sorted_index<3>(vec,1);
for (size_t i=0;i < vec.size()/3;++i)
for (size_t j=0;j<3;++j)
std::cout << access_at<3>(vec,index[i],j) << " ";
std::cout << '\n';
有输出:
1 8 1
2 3 2
3 5 5
2 5 6
2 3 2
3 5 5
2 5 6
1 8 1
如果你真的需要,我会留给你实际复制向量以获得排序的向量。
PS:在上面的第一个版本中,我按照 C 列排序,最后一部分按照要求按照 B 列排序。
PPS:我还是不明白你的代码。我不明白你为什么在谓词中有std::cout
,老实说,我不知道你对sort
的调用应该如何实现你想要的。
【讨论】:
好的,这可能是解决这个问题的好方法,也许这是我应该做的,但我不能通过 2 个月来更改所有代码......以上是关于访问算法的 lambda 函数中的迭代器导致我出现分段错误的主要内容,如果未能解决你的问题,请参考以下文章