0

我正在处理一个处理逗号分隔数据 (CSV) 的 C++ 项目。我所做的是将 .csv 文件中的数据读取到 CsvRow 对象的向量中。
所以,今天我遇到了一个非常奇怪的 std::bad_alloc 异常,它在更奇怪的情况下被抛出。即,我设法获得更多时间直到引发异常的第一个测试用例是将整个 csv 文件读入向量。该文件由 500,000 行组成,大小约为 70MB。该文件像魅力一样被读入内存,但在排序过程几秒钟后,std::bad_alloc 被抛出。它使用了大约 67MB 的 RAM 注意:我正在使用 boost 的 flyweights 以减少内存消耗。

但是,这个测试用例更奇怪:我正在读取一个有几百行的 146KB 文件,这次我在将数据读入向量时遇到了异常,这完全是荒谬的,之前成功读取了 70MB。

我怀疑内存泄漏,但我的机器有 8GB 的​​ RAM,使用 64 位 Windows 8。我正在使用 CodeBlocks 和 MinGW 64 位升压发行版。任何帮助,将不胜感激。这是一段代码,其中 std::bad_alloc 被抛出:

  1. 从 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++;
    }
    
  2. 使用存储在我的类中的内部结构对向量进行排序

    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)哦,还有一点需要指出的是,由于我的 MinGW 是 64 位,我不能使用默认的 32 位 gdb 调试器。32 位 gdb 存在错误,无法与 MinGW 64 一起使用。

编辑:
boost::flyweight<std::string> 在 CsvRow 类中使用的会导致问题吗?

除此之外,这是该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. 不可比性的传递性

更多信息:This question and This Wiki article
实际上,我没有遵循第一个(非自反性),也就是说,如果两个CsvRow对象相等,它不应该“比较”它们并返回true好像它们没问题,但是而是返回falseCsvRow 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
}

感谢所有试图提供帮助的人。请记住此解决方案,以防您遇到类似问题。这很棘手。

4

1 回答 1

1

这个:

distinct_values_.push_back( *new __gnu_cxx::hash_set<std::string,                                     
                            std::hash<std::string> >() );

看起来您正在尝试向向量添加一个默认构造的元素。有一个更简单的方法:

distinct_values_.resize(distinct_values_.size() + 1);

除了更容易输入和更通用之外,它也更正确:我们不应该new在这里输入任何东西,只是在最后创建一个值,我们应该让向量构造它而不是复制它,这可能很浪费。

当然,我们永远不应该尝试delete这些价值观。

于 2013-11-30T03:43:30.970 回答