C++使用std::sort为非常小的std::vector抛出std::bad_alloc异常
C++ throwing a std::bad_alloc exception for very small std::vector using std::sort
我正在C++中进行一个项目,该项目处理逗号分隔数据(CSV)。我所做的是将.csv文件中的数据读取到CsvRow对象的向量中
所以,今天我遇到了一个非常奇怪的std::bad_alloc异常,它在更奇怪的情况下被抛出。也就是说,我设法获得更多时间直到抛出异常的第一个测试用例是将整个csv文件读取到向量中。该文件由500000行组成,大小约为70MB。该文件像符咒一样被读入内存,但在排序过程中几秒钟后,std::bad_alloc被抛出。它使用了大约67MB的RAM注意:我使用boost的轻量级是为了减少内存消耗。
但是,这个测试用例更奇怪:我正在读取一个146KB的文件,其中有几百行,这次我在将数据读取到向量中时遇到了异常,之前成功读取了70MB,这真是太荒谬了。
我怀疑是内存泄漏,但我的机器有8GB的RAM,使用64位Windows8。我使用的是CodeBlocks和MinGW 64位boost发行版。如有任何帮助,我们将不胜感激。下面是一段代码,其中抛出std::bad_alloc:
-
从csv文件读取数据
std::ifstream file(file_name_); int k=0; for (CsvIterator it(file); it != CsvIterator(); ++it) { if(columns_ == 0) { columns_ = (*it).size(); for (unsigned int i=0; i<columns_; i++) { distinct_values_.push_back(*new __gnu_cxx::hash_set<std::string, std::hash<std::string> >()); } } for (unsigned int i=0; i<columns_; i++) { distinct_values_[i].insert((*it)[i]); } all_rows_[k]=(*it); k++; }
-
使用存储在我的类中的内部结构对向量进行排序
struct SortRowsStruct { CsvSorter* r; SortRowsStruct(CsvSorter* rr) : r(rr) { }; bool operator() (CsvRow a, CsvRow b) { for (unsigned int i=0; i<a.size(); i++) { if(a[r->sorting_order_[i]] != b[r->sorting_order_[i]]) { int dir = r->sorting_direction_[i]; switch(dir) { case 0: return (a[r->sorting_order_[i]] < b[r->sorting_order_[i]]); break; case 1: return !(a[r->sorting_order_[i]] < b[r- >sorting_order_[i]]); break; case 2: return true; break; default: return true; } } } return true; } };
然后,我使用std::sort()
对CsvRows 的向量进行排序
SortRowsStruct s(this);
std::sort(all_rows_.begin(), all_rows_.end(), s);
这一行看起来真的很可疑,但我想不出一种更简单的方法来初始化这些哈希集
distinct_values_.push_back( *new __gnu_cxx::hash_set<std::string,
std::hash<std::string> >() );
删除析构函数中的哈希集会使程序崩溃(SIGSEGV)哦,还有一点需要指出,我不能使用默认的32位gdb调试器,因为我的MinGW是64位的。32位gdb已被窃听,无法与MinGW 64配合使用。
编辑:
我在CsvRow类中使用的boost::flyweight<std::string>
会导致问题吗
除此之外,这里还有CsvRow
类的一部分:
private:
std::vector<boost::flyweights::flyweight<std::string> > row_data_;
以及CsvRow
类上过载的[]
运算符:
std::string const& CsvRow::operator[](std::size_t index) const
{
boost::flyweights::flyweight<std::string> fly = row_data_[index];
return fly.get();
}
提前感谢
编辑-已解决:所以,这个问题解决了我的问题,尽管我甚至没有想过。我们传递给std::sort()
的每个自定义比较器都必须是严格的弱排序,即:
1.不灵活
2.不对称
3.及物性
4.不可比性的传递性
更多信息,请访问:此问题和此Wiki文章
事实上,我没有遵循第一个(不可伸缩性),也就是说,如果两个CsvRow
对象都相等,它不应该"比较"它们并返回true
,就好像它们没问题一样,而是返回false
。当CsvRow a
和CsvRow b
都相等时,我只更改了默认返回值,就解决了整个问题。
bool operator() (CsvRow a, CsvRow b)
{
for (unsigned int i=0; i<a.size(); i++) {
if(a[r->sorting_order_[i]] != b[r->sorting_order_[i]]) {
...
...
}
}
return false; //this line does not violate the irreflexivity rule
//return true; //but this one does
}
感谢所有试图提供帮助的人。记住这个解决方案,以防遇到类似的问题。这很棘手。
这:
distinct_values_.push_back( *new __gnu_cxx::hash_set<std::string,
std::hash<std::string> >() );
看起来您正试图将一个默认构造的元素添加到向量中。有一种更简单的方法:
distinct_values_.resize(distinct_values_.size() + 1);
除了更容易键入,更通用之外,它也更正确:我们不应该在这里使用new
,只在最后创建一个值,我们应该让向量构造它,而不是复制它,这可能是浪费。
当然,我们永远不应该尝试delete
这些值。
- 使用std::multimap迭代器创建std::list
- C++中std::resize(n)和std::shrink_to_fit之间的区别
- 来自 std::list 的迭代器 .end() 按预期返回"0xcdcdcdcdcdcdcdcd"但 .begin()
- C++17复制构造函数,在std::unordereded_map上进行深度复制
- 如何导出包含具有"std::unique_ptr"值的"std::map"属性的
- 从持续时间构造std::chrono::system_clock::time_point
- std::具有相同基类的类的变体
- std::向量与传递值的动态数组
- 使用std::vector的OpenCL矩阵乘法
- std::map<struct,struct>::find 找不到匹配项,但是如果我循环通过 begin() 到 end(),我在那里看到匹配项
- std::condition_variable::wait()如何评估给定的谓词
- 如何获取std::result_of函数的返回类型
- std::原子加载和存储都需要吗
- 将对象移动到std::shared_ptr
- 获取错误:在抛出"std::bad::alloc"的实例后终止调用 what(): std::bad_alloc
- "std::vector"在调整大小时引发"bad allocation"异常
- 成员函数 bad() 的 std::ftsream 用于检查
- 正在使用std::string而不是char*bad
- 在抛出 'std::bad _alloc' 的实例后调用终止 what(): std::bad_alloc 在 c++ 中
- What is Scala for: getline(), std::cin.eof(), std::cin.bad()