Привествую. Не могу понять на что расходуется стэк. Вроде как в нем нету тяжёлых объектов или передачи аргументов по значению. Вот код для воспроизведения:
Если уменьшать количество аргументов при вызове join_ranges, то stack overflow перестаёт выскакивать. Поломал голову, но не смог понять куда уходит стэк.
Но решение мне очень не нравится, т.к. в прошлом имел кучу проблем, где на ровном месте при работе с boost::any_range ловил UB. Слишком опасная штука и легко ошибиться.
Ищу решение как это сделать без boost::any_range
PS: Последний Visual Studio 2017. Компилю в x86, запускаю под дебагом, /std:c++17
Здравствуйте, ArtDenis, Вы писали:
AD>Привествую. Не могу понять на что расходуется стэк. Вроде как в нем нету тяжёлых объектов или передачи аргументов по значению. Вот код для воспроизведения:
AD>
AD>Но почему
Я просто прочитал исходник тут и констатировал простой факт: joined_range содержит в себе два итератора, которые содержат в себе два итератора, которые содержат в себе два итератора, которые содержат в себе два итератора, которые содержат в себе два итератора...
AD>Как эту фигню обойти?
По идее должно помочь, но кардинально это проблему не решит. Т.е. я хочу сказать, что должно быть решение лучше, просто я не очень опытен в вариадиках, поэтому сходу написать не могу.
И каждый день — без права на ошибку...
Re[4]: Много boost::range::join приводит к stack overflow
Здравствуйте, B0FEE664, Вы писали:
BFE> ... Т.е. я хочу сказать, что должно быть решение лучше ...
Я уже попытался решить проблему более кардинально. Плюнул на лишние выделения памяти и задействовал std::unique_ptr. Теперь boost::range::joined_range выделяется на куче, а не в стэке.
#include <vector>
#include <iostream>
#include <memory>
#include <boost/range/join.hpp>
template <typename R1, typename R2, typename ... Other>
auto join_ranges(const R1 & r1, const R2 & r2, const Other& ... other)
{
using joined_range_t = boost::range::joined_range<const R1, const R2>;
auto joined_r1_r2 = std::make_unique<joined_range_t>(r1, r2);
if constexpr (sizeof ... (other) == 0)
return joined_r1_r2;
else
return join_ranges(*joined_r1_r2, other...);
}
int main()
{
std::vector<int> v = {1, 2, 3};
auto joined = join_ranges(v, v, v, v, v, v, v, v, v, v, v, v, v, v);
for (int i : *joined)
std::cout << i;
}
Но stack overflow всё равно происходит в конструкторе joined_range! Вот теперь-то он откуда?
Здравствуйте, goloveshin, Вы писали:
G>как вариант, но оно тоже падает...
G> if constexpr (sizeof ... (other) == 0) G> return std::forward<R>(r);
Нету смыла от forward в return. Компилятор сам сделает перемещение в этом случае, если оно возможно. Или я ошибаюсь?
G> else G> return boost::range::join(std::forward<R>(r), join_ranges(std::forward<Other>(other)...));
А это как поможет-то? 1) для меня forward излишен, 2) и у моём и в твоём случае (с forward) передаются ссылки, а они очень мало влияют на размер стэка и в x86 занимают в стеке всего 4 байта
Здравствуйте, ArtDenis, Вы писали:
G>> if constexpr (sizeof ... (other) == 0) G>> return std::forward<R>(r); AD>Нету смыла от forward в return. Компилятор сам сделает перемещение в этом случае, если оно возможно. Или я ошибаюсь?
А всё, понял для чего это. У тебя же возвращаемый тип decltype(auto)
Здравствуйте, ArtDenis, Вы писали:
AD>Но stack overflow всё равно происходит в конструкторе joined_range! Вот теперь-то он откуда?
Слушайте, там удвоение размера на каждом шаге, как не крути, стека не хватит хотя бы просто потому, что конструктор там тоже рекурсивный. Да что стека, просто памяти не хватит!
80
216
488
1032
2120
4296
8648
17352
34760
69576
С такой-то тенденцией, на тридцатом шаге потребуется где-то 64 гигабайта памяти, а на сороковом — 64 терабайта памяти, а если вы захотите объединить это несчастный вектор сотню раз, то количество необходимой памяти превысит число атомов в наблюдаемой вселенной.
Да это просто шедевр какой-то!
И каждый день — без права на ошибку...
Re: Много boost::range::join приводит к stack overflow
Здравствуйте, B0FEE664, Вы писали:
AD>>Но stack overflow всё равно происходит в конструкторе joined_range! Вот теперь-то он откуда? BFE>Слушайте, там удвоение размера на каждом шаге, как не крути, стека не хватит хотя бы просто потому, что конструктор там тоже рекурсивный. Да что стека, просто памяти не хватит!
Да. Но std::make_unique создаёт объект в куче. Возврат из функции через std::unuque_ptr. Стэк не должен задействоваться в таком объёме.