R.pop_back(); - в этой строчке у меня вызываетс...

Erstellt am: 6. September 2025

Beantwortet mit GPT-5 von Chat01

Frage

text
R.pop_back(); - в этой строчке у меня вызывается исключение, но я не понимаю с чем это может быть связано так как на каждой итерации алгоритма у меня удаляется один интервал и вместо него добавляются два новых это просто невозможно чтобы вектор опустел: static __declspec(noalias)std::vector<float> Base_LNA_1_2_Mer_AGP(const uint32_t N, const uint32_t global_iterations, const float a, const float b, const float c, const float d, const float r, const bool mode, const float epsilon, const float seed) noexcept

{

text
if (N == 1u) { const float initial_length = b - a; float dmax = initial_length; const float start_val = ShekelFunc(a, seed); float best_f = ShekelFunc(b, seed); uint32_t schetchick = 0u; std::pair<float, float> x_Rmax = std::make_pair(a, b); std::pair<float, float> y_Rmax = std::make_pair(start_val, best_f); std::vector<float> Extr; Extr.reserve((global_iterations << 1u) + 4u); std::vector<Interval> R; R.reserve(global_iterations + 1u); R.emplace_back(std::make_pair(a, start_val), std::make_pair(b, best_f), N); float Mmax = R.back().M; float m = r * Mmax; const float threshold_03 = 0.3f * initial_length; const float inv_threshold_03 = 1.0f / threshold_03; while (true) { const float new_point = Shag(m, x_Rmax.first, x_Rmax.second, y_Rmax.first, y_Rmax.second, N, r); const float new_value = ShekelFunc(new_point, seed); const std::pair<float, float> promejutochnaya_tochka{ new_point, new_value }; if (new_value < best_f) { best_f = new_value; Extr.emplace_back(best_f); Extr.emplace_back(new_point); } std::pop_heap(R.begin(), R.end(), Compare); Interval promejutochny_otrezok = std::move(R.back()); R.pop_back(); const size_t r_size = R.size(); const float len2 = promejutochny_otrezok.end.first - new_point; const float len1 = new_point - promejutochny_otrezok.start.first; const float dmin = len1 < len2 ? len1 : len2; if (++schetchick == global_iterations || dmin < epsilon) { Extr.emplace_back(dmin); Extr.emplace_back(schetchick); return Extr; } Interval curr(promejutochny_otrezok.start, promejutochnaya_tochka, N); Interval curr1(promejutochnaya_tochka, promejutochny_otrezok.end, N); const float currM = curr.M > curr1.M ? curr.M : curr1.M; if (len2 + len1 == dmax) { dmax = len2 > len1 ? len2 : len1;

#pragma loop(ivdep)
for (size_t i = 0u; i < r_size; ++i) {
const float len = R[i].end.first - R[i].start.first;
if (len > dmax) {
dmax = len;
}
}
}

text
if (mode) { if (threshold_03 > dmax && schetchick % 3u == 0u || 10.0f * dmax < initial_length) { if (currM > Mmax) { Mmax = currM; m = r * Mmax; } const float progress = fmaf(-inv_threshold_03, dmax, 1.0f); const float alpha = fmaf(progress, progress, 1.0f); const float betta = 2.0f - alpha; const float MULTIPLIER = (1.0f / dmax) * Mmax; const float global_coeff = fmaf(MULTIPLIER, r, -MULTIPLIER); const float GLOBAL_FACTOR = betta * global_coeff; curr.ChangeCharacteristic(fmaf(GLOBAL_FACTOR, len1, curr.M * alpha), N); curr1.ChangeCharacteristic(fmaf(GLOBAL_FACTOR, len2, curr1.M * alpha), N);

#pragma loop(ivdep)
for (size_t i = 0u; i < r_size; ++i) {
const float len_item = R[i].end.first - R[i].start.first;
R[i].ChangeCharacteristic(fmaf(GLOBAL_FACTOR, len_item, R[i].M * alpha), N);
}
std::make_heap(R.begin(), R.end(), Compare);
}
else {
if (currM > Mmax) {
Mmax = currM;
m = r * Mmax;
curr.ChangeCharacteristic(m, N);
curr1.ChangeCharacteristic(m, N);
#pragma loop(ivdep)
for (size_t i = 0u; i < r_size; ++i) {
R[i].ChangeCharacteristic(m, N);
}
std::make_heap(R.begin(), R.end(), Compare);
}
else {
curr.ChangeCharacteristic(m, N);
curr1.ChangeCharacteristic(m, N);
}
}
}
else {
if (currM > Mmax) {
Mmax = currM;
m = r * Mmax;
curr.ChangeCharacteristic(m, N);
curr1.ChangeCharacteristic(m, N);
#pragma loop(ivdep)
for (size_t i = 0u; i < r_size; ++i) {
R[i].ChangeCharacteristic(m, N);
}
std::make_heap(R.begin(), R.end(), Compare);
}
else {
curr.ChangeCharacteristic(m, N);
curr1.ChangeCharacteristic(m, N);
}
}

text
R.emplace_back(std::move(curr)); std::push_heap(R.begin(), R.end(), Compare); R.emplace_back(std::move(curr1)); std::push_heap(R.begin(), R.end(), Compare); const Interval& top = R.front(); x_Rmax = std::make_pair(top.start.first, top.end.first); y_Rmax = std::make_pair(top.start.second, top.end.second); } }

Gedanke

Thought for 54s

Antwort

Коротко: R.pop_back() падает не потому, что «вектор обязательно пустеет логически», а потому что в какой-то итерации к моменту вызова pop_back() у R действительно size()==0 (или разрушается «битый» элемент). Ниже — самые частые причины именно при таком паттерне pop_heapmove R.back()pop_back() и что проверить.

Что проверить в первую очередь

  1. Гарантируете ли непустоту перед pop_heap/pop_back
  • Перед std::pop_heap(R.begin(), R.end(), Compare); добавьте защиту:
    cpp
    if (R.empty()) { /* лог/ассерт */ return Extr; }
    Если сработает — значит где-то ранее вы вышли из цикла без «восполнения» кучи.
  1. Правильность логики выхода
  • В вашем коде из функции можно выйти после того как вы уже вынули элемент из кучи, но до того как добавили два новых:
    cpp
    std::pop_heap(...); Interval i = std::move(R.back()); R.pop_back(); // уменьшили size ... if (++schetchick == global_iterations || dmin < epsilon) { return Extr; // выход без возвращения интервала назад }
    Это нормально (вы просто выходите), но на следующей итерации цикла вы уже не будете (вы вышли). Так что эта часть не делает R пустым «для следующего pop_back».
    Если исключение возникает именно на pop_back в той же итерации — значит проблема не в этом «раннем выходе».
  1. Корректность компаратора Compare
  • Для алгоритмов кучи Compare обязан задавать строгий слабый порядок (Strict Weak Ordering). Любые нарушения (недетерминизм, зависимость от меняющихся полей без переупорядочивания, NaN в сравниваемых значениях и т. п.) приводят к UB и повреждению внутреннего состояния вектора/кучи, что легко «выстрелит» на pop_back.
  • Вы изменяете R[i].M и длины интервалов. Где вы меняли ключи кучи, вы вызвали std::make_heap(R.begin(), R.end(), Compare); — это хорошо. Убедитесь, что во всех ветках, где меняются поля, влияющие на порядок (то, по чему сравнивает Compare), вы действительно делаете reheapify.
  1. Изменение элементов без reheapify
  • В ветке:
    cpp
    else { curr.ChangeCharacteristic(m, N); curr1.ChangeCharacteristic(m, N); // R[i] не меняли → make_heap не нужен }
    Это ок, если Compare не зависит от других полей в R[i]. Но если ChangeCharacteristic косвенно влияет на то, как Compare сравнит элементы (например, через общий глобальный коэффициент), потребуется make_heap.
  1. Исключение/авария в деструкторе/перемещении Interval
  • Строка:
    cpp
    Interval promejutochny_otrezok = std::move(R.back()); R.pop_back();
    вызывает деструктор элемента на конце. Если у Interval деструктор бросает (нельзя), assert’ится, или опирается на инварианты, нарушающиеся после перемещения — исключение прилетит на pop_back(). Проверьте:
    • Деструктор ~Interval()noexcept и безопасен для «перемещённого» состояния.
    • Move-ctor/Move-assign корректно «зануляют» ресурсы.
    • Нет «двойного освобождения» ресурсов (сырой delete/free).
  1. NaN и сравнения с float
  • Если Compare использует float поля (M, длина интервала) и туда закрадывается NaN, любые сравнения становятся непредсказуемыми → куча ломается.
    Проверьте расчёты: dmax, GLOBAL_FACTOR, MULTIPLIER = (1.0f / dmax) * Mmax (если dmax==0, деление!), fmaf, т. п. Добавьте ранние проверки:
    cpp
    assert(std::isfinite(dmax) && dmax > 0); assert(std::isfinite(Mmax)); assert(std::isfinite(curr.M) && std::isfinite(curr1.M));
  1. Начальное состояние кучи
  • После R.emplace_back(...) вы не делаете make_heap. Для size()==1 это ок (куча тривиальна). Но как только размер >1, вы строго поддерживаете кучу через push_heap — это правильно. Убедитесь, что нигде не попадает во R элемент обходя push_heap.
  1. Порядок pop_heap/move/pop_back
  • Ваш порядок корректный:
    1. pop_heap → максимальный элемент уходит в back();
    2. move из back();
    3. pop_back разрушает перемещённый элемент.
      Не меняйте местами.

Как отладить быстро

  • Включите проверки в отладке (MSVC): _ITERATOR_DEBUG_LEVEL=2, ассерты на пустоту и std::isfinite.
  • Логируйте размер до и после операций:
    cpp
    assert(!R.empty()); std::pop_heap(...); // здесь size тот же // R.back() валиден Interval x = std::move(R.back()); R.pop_back(); // size--, деструктор
  • На время отладки замените Interval на POD/тривиальный тип или сделайте пустой деструктор — если падение исчезло, проблема в деструкторе/перемещении.

Возможное «пуленепробиваемое» исправление

Если выяснится, что иногда вы меняете ключи элементов без reheapify, то самый простой «страховочный» шаг — всегда пересобирать кучу после любых модификаций полей, влияющих на порядок:

cpp
// После любых ChangeCharacteristic, которые влияют на Compare: std::make_heap(R.begin(), R.end(), Compare);

И убедитесь, что деления на dmax безопасны (dmax>0) и что Compare — чистая функция по полям элемента.

Если пришлёте код Interval и Compare, скажу точнее, что именно ломает кучу/деструктор.

Diesen Q&A teilen