0

コンマ区切りデータ (CSV) を扱う C++ のプロジェクトに取り組んでいます。私がしているのは、.csv ファイルから CsvRow オブジェクトのベクトルにデータを読み取ることです。
それで、今日、私は本当に奇妙な std::bad_alloc 例外がはるかに奇妙な状況でスローされることに遭遇しました。つまり、例外がスローされるまでもう少し時間を確保できた最初のテスト ケースは、csv ファイル全体をベクターに読み込むことでした。ファイルは 500,000 行で構成され、そのサイズは約 70MB です。ファイルは魅力のようにメモリに読み込まれましたが、ソート手順の数秒後に std::bad_alloc がスローされます。約 67MB の RAM を使用しました。注: メモリ消費を抑えるために、boost の flyweights を使用しています。

しかし、このテスト ケースはさらに奇妙でした。数百行の 146KB のファイルを読み込んでいるのですが、今回はデータをベクトルに読み込んでいるときに例外が発生しました。

メモリ リークの疑いがありますが、私のマシンには 8 GB の 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) がクラッシュします。もう 1 つ注意すべき点は、MinGW が 64 ビットであるため、デフォルトの 32 ビット gdb デバッガを使用できないことです。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. 非比較性の推移性

詳細: This question and This Wiki article
実際、私は最初のもの (非反射性) には従いませCsvRowんでしtrueた。代わりに返品してfalseください。CsvRow aCsvRow 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