LINUX.ORG.RU

std::vector валится на push_back/emplace_back с сегфолтом О_О

 ,


1

5

Сабж.

Валится при size()==16.

Валится редко, но достаточно одного раза.

Переписал сначала добавление элементов в std::list, затем для вектора resize и копирование из списка - все работает.

Но вообще то это странный косяк... кто нить сталкивался?

★★★★★

Последнее исправление: AIv (всего исправлений: 1)
Ответ на: комментарий от anonymous

Вы знате, лично меня Ваше мнение не интересует ни по какому поводу. «Вообще от слова совсем».

Бай.

ЗЫ ЛОР все тот же ЛОР... сколько лет прошло, а так и не запретили анонимусов;-(

AIv ★★★★★
() автор топика
Ответ на: комментарий от anonymous

А почему вы не хотите разобраться?

Потому что у меня банально нет на это времени. Насчет объемов данных не уверен, но у нас основные объемы не в std::vector лежат. Хотя от задачи зависит, кое где и в нем, но без push/emplace_back ес-но.

AIv ★★★★★
() автор топика
Ответ на: комментарий от AIv

В проблеме не разобрался, минимальный код, чтобы те, кому интересно, могли копать дальше, не предоставил, назначил в виноватые стандартные методы стандартного контейнера одной из самых распространенных реализаций(это, напомню, не разобравшись в проблеме, а значит, без оснований). И кто ты после этого?

anonymous
()
Ответ на: комментарий от AIv

Короче std::vector::emplace_back/push_back нестабильное гавно.

Намного вероятнее, что с std::vector все в порядке, а «нестабильное гавно» — это ваш прикладной код.

Поведение std::vector::push_back и std::list::push_back отличается в одном очень важном месте: list::push_back не перемещает уже находящиеся в контейнеры элементы, тогда как vector::push_back это делает, когда заканчивается ранее выделенный буфер для хранения элементов контейнера.

Что и заставляет думать, что проблема таки у вас: ваш код не переживает перемещения в памяти уже добавленных в vector элементов. А уже в чем конкретно это проявляется, нужно разбираться. Может у вас плохо написан тип элемента, который хранится в контейнере. Например, неправильно реализованы copy constructor/operator (или даже move constructor/operator).

А может у вас используется код вида:

vector<YourType> vec;
vec.push_back( construct_new_item() );
auto & first = vec[0];
vec.push_back( construct_new_item() );
auto & second = vec[1];
vec.push_back( construct_new_item() );
first.call_some_mutable_operation(); // Oops #1
second.call_some_mutable_operation(); // Oops #2
После любого упсов в таком коде ваша программа может упасть где угодно и когда угодно, т.к. предугадать что и где будет запорчено в памяти невозможно.

Вы же никакой полезной информации не предоставили, понять что у вас в векторе храниться невозможно. Узнать, как вы с вектором работаете тоже. А экстрасенсов здесь нет.

а с этой фигней уже ЕМНИП второй раз напарываюсь - на тестах все ок, под нагрузкой сегфолтится или валится в деструкторе.

Ну значит и тесты писать не умеете. Помимо элементарных unit-тестов в проекте желательно иметь и тесты, которые имитируют реальную нагрузку, если не большую.

eao197 ★★★★★
()
Ответ на: комментарий от AIv

Резюмируя тред: Alv напоролся на баг при использовании std::vector. Минимального примера, воспроизводящего ошибку, не предоставил, аргументируя это отсутствием времени. Подпёр костылями и набросился с обвинениями в адрес разрабов gcc, лоровцев и анонимусов.

Я думаю, это скорее Alv не нужно писать на лор и тратить время лоровцев и анонимусов.

jeuta ★★★★
()
Ответ на: комментарий от jeuta

А я думаю Вам не нужно говорить что мне делать (если не хотите тратить свое и мое время):-).

AIv ★★★★★
() автор топика
Ответ на: комментарий от eao197

Если бы Ваше предположение было верным, оно упало бы значительно раньше.

Кстати при вызове reserve emplace не должен приводить к перемещению данных (пока место есть).

AIv ★★★★★
() автор топика
Ответ на: комментарий от slovazap

О-о-о, намного профессиональнее размышлять какой лучше костыль воткнуть

Да тут даже не костыль, а тупо заметание проблемы под ковёр даже не понимая её сути. Вангую, что потом выстрелит в другом месте, а дальше будут россказни про «плохой стл».

DarkEld3r ★★★★★
()
Ответ на: комментарий от BRE

Вангую, что ТС главное отчет сдать. Код один хрен пойдет на выброс.

anonymous
()
Ответ на: комментарий от AIv

сколько лет прошло, а так и не запретили анонимусов;-(

у кого учётку угнал?

anonymous
()
Ответ на: комментарий от yoghurt

realloc в std::vector? ORLY?

А как ты думаешь он увеличивает занимаемую память?

Кстати можно легко проверить, на нём ли падает. Перед push_back делать reserve (или заранее достаточно резервировать).

monk ★★★★★
()
Ответ на: комментарий от AIv

Кстати при вызове reserve emplace не должен приводить к перемещению данных (пока место есть).

Откуда мне знать, что вы reserve вызываете в нужном месте и с правильными параметрами?

Т.к. вашего кода никто в глаза не видел, то равновероятным представляется и то, что код написан хорошо, и то, что в нем баг на баге.

eao197 ★★★★★
()
Ответ на: комментарий от monk

Я делал (во втором случае когдаа валился в деструкторе) - не помогло.

Вообще оно могет и просьо новый кусок выделить и туда скопировать данные.

AIv ★★★★★
() автор топика
Ответ на: комментарий от eao197

Простите Евгений, но целью данного топика не является создание знания о верности/не верности моего кода у читающих. Я бы может его и выложил целиком, но тут и так потоки флейма от анонимусов в которых нормальные сообщения трудно вылавливать - с кодом будет вообще ад.

AIv ★★★★★
() автор топика
Ответ на: комментарий от AIv

Я делал (во втором случае когдаа валился в деструкторе) - не помогло.

Падало по-прежнему на push_back? Не на reserve?

Просто размер 16 наводит на мысль, что в этот момент происходит аллокация. Если делать reserve, то её в push_back быть не должно

monk ★★★★★
()
Ответ на: комментарий от monk

Да, я об этом думал. Падало на деструкторе как и раньше, но там был еще swap и clear.

Вообще нажо попробовать 1й кейс который валился на пуше попробовать с reserve.

AIv ★★★★★
() автор топика
Ответ на: комментарий от AIv

«Создавать» знание о потрохах STL, основываясь на потенциальном говнокоде куда продуктивнее...

ЗЫ Написать минимальный код в несколько десятков строк непосильная задача для РАН?

anonymous
()
Ответ на: комментарий от anonymous

Минимальный код будет работать. И я вообще то знание у себя создаю - обучение упоротой школоты на лоре меня давно уже не интересует.

AIv ★★★★★
() автор топика
  • Попробуй std::deque.
  • Используй .at(...)
  • Проверь dmesg на ошибки памяти, если есть ECC
AlexVR ★★★★★
()
Ответ на: комментарий от monk

А как ты думаешь он увеличивает занимаемую память?

Аллокатором. realloc и сходные с ним функции использовать нельзя, потому что, в общем случае, перемещение плюсовых объектов — это совсем не то же самое, что копирование куска памяти.

Gvidon ★★★★
()
Ответ на: комментарий от AIv

целью данного топика не является создание знания о верности/не верности моего кода у читающих

Не берусь судить за всех анонимов, но, думаю, что с примерами кода многие из отметившихся здесь с удовольствием бы попробовали разобраться с крахом на обращении к push_back.

Просто попытка сказать, что проблема именно в vector::push_back без демонстрации кода, объективно, выглядит ну очень странно. Отсюда и такая реакция у читателей темы.

eao197 ★★★★★
()
Ответ на: комментарий от eao197

Евгений, и все эти желающие не обнаружили бы сегфолта и принялись бы выть еще громче. Вы как первый раз в этом скорбном месте:-)

AIv ★★★★★
() автор топика
Ответ на: комментарий от anonymous

Потому что желание свалить все на библиотеку/framework/ЯП — первый признак плохого (если не сказать грубее) программиста. Зачем такому разбираться?

Quickern ★★
()
Ответ на: комментарий от AIv

все эти желающие не обнаружили бы сегфолта и принялись бы выть еще громче.

Во-первых, не факт, что не обнаружили бы. Вообще, один из самых действенных способов обнаружить сложную ошибку — это объяснить алгоритм работы кода кому-то другому. В процессе объяснения у самого в голове знания упорядочиваются и проблемные места всплывают сами собой. Проверено многократно и не только на себе.

Во-вторых, тезис о некачественной работе vector::push_back выдвинули вы, вам его и доказывать. От чего вы уклоняетесь, к сожалению. Собственно, вашим оппонентам ничего другого и не остается, как признать вашу неправоту.

Ну и вообще, в STL vector это одна из самых первых, самых простых и надежных структур. Ее оттестировало столько людей в стольких условиях, что это даже вообразить невозможно. Так что грешить на vector — это последнее дело.

eao197 ★★★★★
()
Ответ на: комментарий от monk

А как ты думаешь он увеличивает занимаемую память?

delete + new. Не забываем, что элементами вектора может быть всё, что угодно, и далеко неспроста он требует наличие copy constructor-а.

yoghurt ★★★★★
()
Ответ на: комментарий от eao197

Мне не удалось воспроизвести ошибку на простом коде.

И это как бы не научная дискуссия, что бы я что то кому то доказывал.

AIv ★★★★★
() автор топика

Походу дела у тебя хранимые объекты ведут себя не правильно (ошибки в тех местах, где они создаются, копируются и удаляются). Смотри конструктор по умолчанию, конструктор копирования, деструктор. Оцени количество их вызовов:

#include <iostream>
#include <vector>
#include <deque>

template<int I> class A {
public:
  A() {
    i = I;
    std::cout << " A<" << i << ">()\n";
  };
  A(const A& a) {
    i = a.i;
    std::cout << " A<" << i << ">(A&)\n";
  };
  ~A() {
    std::cout << " ~A<" << i << ">()\n";
  };
private:
  int i;
};

int main() {
  const size_t N=5;
  std::cout << "Init\n";
  std::vector< A<1> > vs;
  std::vector< A<2> > vs_pre(N);
  std::deque< A<3> > ds;
  std::cout << "Fill\n";
  for(size_t i=0; i<N; i++) {
    vs.push_back(A<1>());
    vs_pre[i] = A<2>();
    ds.push_back(A<3>());
  }
  std::cout << "Drop\n";
}

AlexVR ★★★★★
()
Ответ на: комментарий от AIv

Мне не удалось воспроизвести ошибку на простом коде.

Так может просто привести фрагмент реального кода, в котором ошибка диагностирована? Как-то же вы место сбоя определили, значит есть какой-то контекст вокруг него.

И это как бы не научная дискуссия, что бы я что то кому то доказывал.

Ну а это вы уже сами определяете. Если вы бездоказательно говорите, что «push_back — нестабильное гавно», то не стоит удивляться ответному «ниасилил»...

Если же вы говорите, что делаю так и так, вроде бы все правильно, но на push_back-е все валится, то и отношение в ответ будет другое. По крайней мере от адекватной части аудитории.

eao197 ★★★★★
()
Ответ на: комментарий от AIv
  • POD-типы разными бывают.
  • Потоки/OpenMP используются?
  • -Wall и прочее использовал?
AlexVR ★★★★★
()
Ответ на: комментарий от AIv

И это как бы не научная дискуссия, что бы я что то кому то доказывал.

И поэтому можно кидаться какашками в STL. Но если анонимы бросят в ответ, это ай-яй-яй. Я всё правильно понял?

Хотя троллинг качественный, надо признать.

i-rinat ★★★★★
()
Ответ на: комментарий от AIv

Ьам этих векторов неск.млн.

А может тут и скрылась проблема? Каков процент использованной памяти? Утечка памяти? Большая фрагментарность данных?

AlexVR ★★★★★
()
Ответ на: комментарий от AIv

О, я готов отдавать все что сам получаю - в данном конкретном случае одно большое человеческое спасибо в час.

Выкладывайте код тогда, вместе разберёмся.

Можно я сам буду оценивать какие советы для меня полезные а какие нет?

Нельзя, поскольку вы не в состоянии адекватно это оценить.

slovazap ★★★★★
()
Ответ на: комментарий от slovazap

Нельзя, поскольку вы не в состоянии адекватно это оценить.

Будете продолжать в том же духе - добавлю в список друзей. Не по злобе, а просто что бы на Вас не отвлекаться.

AIv ★★★★★
() автор топика
Ответ на: комментарий от monk

Интересно деффки пляшут

Без reserve:

void SpaceModel::mk_well( double x, double y,     // координаты скважины по латерали
                          double z_t, double z_b, // максимальный интервал по глубине
                          std::vector<GeoPhysPlastWell> &dstW, bool out) const {
        GeoPhysPlastWell well;
        if(out) WOUT(x, y, z_t, z_b);
        std::vector<GeoPhysPlastWell> W; // W.reserve(1024);
        if(out) WOUT(x, y, z_t, z_b, W.size());
        for(int i=0; i<(int)plasts.size(); i++){
                if(out) WOUT(i, W.size());
                if(plasts[i]->calc(x, y, well)){ 
                        if(out) WOUT(1, i, plasts.size(), W.size());
                        if(well.z_t>z_t) well.z_t = z_t;
                        if(out) WOUT(2);
                        if(well.z_b<z_b) well.z_b = z_b;
                        if(out) WOUT(W.size(), well.z_b<well.z_t);
                        if(well.z_b<well.z_t) W.push_back(well); // <<=== СЕГФОЛТ ЗДЕСЬ
                        if(out) WOUT(4);
                }               
                if(out) WOUT(i, plasts[i]->ID, (int)W.size(), well.plastID, well.z_t, well.z_b, well.par_t.Vp);
        }
        well.par_t = *this; well.z_t = z_t; well.z_b = z_b;
        well.d_par.Vp = well.d_par.Vs = well.d_par.sigma = 0.;
        well.plastID = 0; W.push_back(well);
        if(out) WOUT((int)W.size());
        dstW.resize(W.size());
        int i = 0; for(auto j=W.begin(); j!=W.end(); ++j) dstW[i++] = *j;
}
сегфолт при W.size()==4

C reserve() оно сегфолтится на reserve() O_O?

AIv ★★★★★
() автор топика
Ответ на: Интересно деффки пляшут от AIv

Очень хочется посмотреть на определение GeoPhysPlastWell, там ведь какие-то указатели хранятся...

PS. Вместо повторяющихся if(out)WOUT было бы проще сделать WOUT_IF и писать что-то вроде:

WOUT_IF(out, 1, i, plasts.size(), W.size());

eao197 ★★★★★
()
Ответ на: комментарий от eao197

отношение в ответ будет другое. По крайней мере от адекватной части аудитории.

К адекватной части относится скажем monk - он как обычно сразу понял о чем речь и отвечал по делу. И почему же его не смутило отсутствие кода?;-)

Евгений, реакция большей части аудитории вполне понятна, я сам всегда так говорю когда валится stl контейнер. Но для меня целью было не убедить в чем то аудиторию, а быстро решить проблему - я ее в итоге таки решил. Вот я выложил фрагмент кода (гл образом по Вашим настойчивым просьбам) - щас увидите что будет.

И я грешу не на весь std::vector а на его конкретные методы push_back/emplace_back - для вектора они вообще то выглядят извращением, у меня это не первый случай когда они приводят ко всяким неприятным казусам на совершенно обычных POD-типах без всяких указателей, итераторов и пр. Вы можете конечно сказать что я эти методы ниасилил - ну дык результат то не меняется от этого, нафик мне методы при использовании которого приходится помнить о 100500 всевозможных траблах...

AIv ★★★★★
() автор топика
Ответ на: Интересно деффки пляшут от AIv

Ну и если цель данной процедуры — полностью заменить содержимое dstW на W, то вместо:

int i = 0; for(auto j=W.begin(); j!=W.end(); ++j) dstW[i++] = *j;

лучше было бы написать:

dstW.swap(W);

Или, с учетом того, что вы уже используете возможности C++11, тупо возвращать W как результат функции mk_well.

eao197 ★★★★★
()
Ответ на: комментарий от eao197

Ни одного указателя.

struct GeoPhysPar{
        float Vp, Vs, sigma;
        //      float epsilon, gamma, delta, theta;
        //      GeoPhysPar(): epsilon(0.), gamma(0.), delta(0.), theta(0.){}
        inline GeoPhysPar operator + (const GeoPhysPar &P) const {
                GeoPhysPar R; 
                R.Vp = Vp+P.Vp;
                R.Vs = Vs+P.Vs;
                R.sigma = sigma+P.sigma;
                return R;
        }
        inline GeoPhysPar operator - (const GeoPhysPar &P) const {
                GeoPhysPar R; 
                R.Vp = Vp-P.Vp;
                R.Vs = Vs-P.Vs;
                R.sigma = sigma-P.sigma;
                return R;
        }
        inline GeoPhysPar operator * (double x) const {
                GeoPhysPar R; 
                R.Vp = Vp*x;
                R.Vs = Vs*x;
                R.sigma = sigma*x;
                return R;
        }
};
struct ZRange{ 
        float z_t, z_b; 
        int plastID; 
        ZRange():plastID(-1){}
        ZRange(float z_t_, float z_b_, int plastID_): z_t(z_t_), z_b(z_b_), plastID(plastID_) {}
        inline bool operator < (const ZRange &other) const { return z_b>=other.z_t; }
};
struct GeoPhysPlastWell: public ZRange{
        float z_scale;
        GeoPhysPar par_t, d_par;
        int calc(double z, GeoPhysPar &par) const; // return plastID or -1
        //      inline bool operator >(const ZRange &other) const {     return z_b < other.z_t; }
};

PS. Вместо повторяющихся if(out)WOUT было бы проще сделать WOUT_IF и ..

Вот видите, Вы уже начинаете давать советы. Вы же не знаете что этот макрос и зачем;-) По ряду причин подобное использование для него нехаракетрно, это тут так получилось...

AIv ★★★★★
() автор топика
Ответ на: комментарий от AIv

а быстро решить проблему - я ее в итоге таки решил

Очень опасаюсь, что вы просто спрятали проблему глубже. Похоже, ошибка наведенная. И вам повезло, что вы столкнулись с местом, где она стабильно проявлялась. Это давало шансы на ее нахождение и исправление.

Судя по вашему коду, очень сильно могут помочь:

- включение максимального уровня предупреждений у компилятора (всяческие -Wall -Wextra и т.д.);

- использование еще одного компилятора (того же clang++);

- использование внешних инструментов вроде анализатора из clang-а и/или valgrind-а.

Но это при условии, что вы действительно хотите найти ошибку. А не обходить ее еще раз.

eao197 ★★★★★
()
Ответ на: комментарий от eao197

В работающем оригинале W std::list. С циклом существенным является отсутствие оверхеда по памяти в dstW - их таких много.

AIv ★★★★★
() автор топика
Ответ на: комментарий от AIv

В работающем оригинале W std::list. С циклом существенным является отсутствие оверхеда по памяти в dstW - их таких много.

Был бы W vector-ом, то у swap-а бы вообще никакого оверхеда не было бы.

Скажите, а plasts — это член SpaceModel?

Может ли быть так, что работа с методами SpaceModel идет из разных потоков? Т.е. в одном потоке работает mk_well, а во втором кто-то модифицирует plasts?

eao197 ★★★★★
()
Ответ на: комментарий от eao197

Ох... Вы правда читали весь тред?

- включение максимального уровня предупреждений у компилятора (всяческие -Wall -Wextra и т.д.);

-Wall ес-но включено и молчит.

- использование еще одного компилятора (того же clang++);

возможно, но это связанено с рядом проблем, можно я не буду их озвучивать?

- использование внешних инструментов вроде анализатора из clang-а и/или valgrind-а.

Про valgrind я уже писал - при его производительности я не дождусь результатов отладки.

Но это при условии, что вы действительно хотите найти ошибку. А не обходить ее еще раз.

Евгений, благодарю Вас за Ваши оценочные суждения. Простите что повторяюсь - можно я сам буду решать что и как мне делать?;-)

AIv ★★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.