Я работаю над проектом на С++, который имеет дело с данными, разделенными запятыми (CSV). Что я делаю, так это читаю данные из файла .csv в вектор объектов CsvRow.
Итак, сегодня я столкнулся с очень странными исключениями std::bad_alloc, возникающими в гораздо более странных ситуациях. А именно, первым тестовым случаем, в котором мне удалось получить немного больше времени, пока я не сгенерирую исключение, было чтение всего файла csv в вектор. Файл состоит из 500 000 строк и имеет размер около 70 МБ. Файл был прочитан в память как шарм, но затем, через несколько секунд в процедуре сортировки, выбрасывается std::bad_alloc. Он использовал примерно 67 МБ ОЗУ. Примечание. Я использую облегченные веса Boost, чтобы уменьшить потребление памяти.
НО, этот тестовый пример был еще более странным: я читаю файл размером 146 КБ с несколькими сотнями строк, и на этот раз я получил исключение при чтении данных в вектор, что совершенно нелепо, когда ранее было успешно прочитано 70 МБ.
Я подозреваю утечку памяти, но моя машина имеет 8 ГБ ОЗУ и использует 64-разрядную версию Windows 8. Я использую CodeBlocks и 64-разрядный дистрибутив MinGW 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.
Изменить:
Может ли 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. Транзитивность несравнимости
Дополнительные сведения см. по адресу: Этот вопрос и Эта статья 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_
, и я могу почти гарантировать, что вы правы в том, что эта строка абсолютно отвратительна. Когда вы говорите Удаление этих хеш-наборов в деструкторе, происходит сбой программы.. - в деструкторе чего?? Из того, что я вижу, они не должны быть динамически распределены вообще. - person WhozCraig   schedule 30.11.2013new
что-то разыменовываете указатель на то, что вы только что выделили, а затем копируете инициализированный объект в другой новый объект, выделенныйvector::push_back()
. Вы никогда не сохраняете указатель, возвращенныйnew
, поэтому вы никак не можете егоdelete
. Тем временемpush_back()
создает новые объекты в вашемvector
, в которые вы просто копируете. Если вы попытаетесьdelete
эти объекты, вам будет больно; они являются частью хранилища, которым управляетvector
. - person Joe Z   schedule 30.11.2013*new
. Что происходит, когда вы пишете:distinct_values_.push_back( __gnu_cxx::hash_set<std::string, std::hash<std::string> >() );
- person Joe Z   schedule 30.11.2013distinct_values_
равноstd::vector<__gnu_cxx::hash_set<std::string, std::hash<std::string> > > distinct_values_;
, которое представляет собой векторhash_set
, который мне нужен для каждого столбца. Я попытался удалить сегмент*new
, а также удалил строки удаления в деструкторе класса, в котором они содержатся. - person Nino   schedule 30.11.2013std::sort
я получаю код выхода0xFF
. - person Nino   schedule 30.11.2013