рантайме variant<monostate, not_null<A*>, not_null<B*>>::emplace(not_null<B*>&&), (это GCC 10, libstdc++), причём по коду примерно понятно, почему такое возможно. В двух словах, вызывается этот метод emplace<size_t, not_null<B*>>:
https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/include/std/variant#L1512-L1516
Который вызывает вот эту ветку, в которой дёргается variant::operator=(variant&&):
https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/include/std/variant#L1533-L1540
Этот operator= генерируется компилятором:
https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/include/std/variant#L1407
И вниз по пути сгенерированного оператора вызывается operator= у _Move_assign_base:
https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/include/std/variant#L687-L707
Который - тадам - для варианта вызывает снова тот же variant::emplace<size_t, not_null<B*>>:
https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/include/std/variant#L707
Я не прав? Или libstdc++ не прав?
Воспроизводится на годболте. Господа знатоки libstdc++, скажите, что мне делать, у меня TDesktop новый крашится: https://godbolt.org/z/rK8GPMhWj Инклудим gsl::not_null, потом такой пример: struct A { }; using gsl::not_null; using V = std::variant<std::monostate, not_null<A*>>; int main() { V v; A a; not_null<A*> p = &a; v.emplace<1u>(std::move(p)); std::cout << v.index(); return 0; } И он сегфолтится на libstdc++ на последних clang / gcc. И работает на libc++. Так ведь не должно быть? Если комментируешь строчку с .emplace<1u>(... — то не сегфолтится, работает.
Ломает что? Здесь проблема в variant, он не должен стек-оверфлоу на таком коде ни для каких типов.. В стектрейсе только вызовы изнутри variant, никакие методы самого not_null там даже не вызываются.
Вот я примерно показал, на чём рекурсия. variant::emplace -> variant::operator= -> _Move_assign_base::operator= -> variant::emplace.
Минимизированный пример: #include <variant> struct not_null { public: template <typename U> constexpr not_null(U&& u) { } not_null& operator=(const not_null& other) = default; }; int main() { std::variant<std::monostate, not_null> v; v.emplace<1u>(not_null{ 42 }); return v.index(); }
Обсуждают сегодня