Вот код:
#include <vector>
#include <functional>
class TestClass {
public:
const std::vector<int> &getStuff() const {
return callback();
}
protected:
std::function<const std::vector<int> &()> callback = []() {
static const std::vector<int> dummy;
return dummy;
};
};
int main()
{
TestClass test;
const auto& vec = test.getStuff();
vec.size(); // segfault
return 0;
}
Я не понимаю, почему он должен вести себя так. Я подозреваю, что есть какое-то «известное» правило относительно лямбд или std::function
, но я не могу найти подходящие ключевые слова для этой проблемы, поэтому я здесь.
Протестировано на GCC 11 и Clang 14 Ubuntu.
С этой лямбдой:
[]() {
static const std::vector<int> dummy;
return dummy;
};
Компилятор делает вывод, что возвращаемое значение — это std::vector<int>
по значению (а не ссылка на std::vector<int>
).
Затем, когда он преобразуется в std::function<const std::vector<int> &()>
, std::function
вернет ссылку на временную копию, возвращенную из лямбды.
Эта ссылка висит и отсюда ваш SEGFAULT.
Чтобы это исправить, вы можете явно указать тип возвращаемого значения для лямбды:
//---vvvvvvvvvvvvvvvvvvvvvvvvvv--
[]() -> const std::vector<int>& {
static const std::vector<int> dummy;
return dummy;
};
Как прокомментировал @Evg ниже, вы также можете использовать auto &
для достижения того же результата (компилятор определит правильный тип и будет использовать ссылку из-за &
):
[]() -> auto & {
// ...
}
@ligazetom C++ известен множеством острых углов ;-)
Я работаю с C++ +- 10 лет, и теперь я чувствую себя как мем о прыжке на грабли. Что ж, увидимся ещё через 10.
-> auto&
тоже должно работать.
@Evg - хорошая мысль, - добавил примечание.
Господи, 6 часов... на самом деле не используется для явного объявления типов возвращаемых значений, но, если честно, это открывает глаза. Мне нужно пересмотреть свой старый код, чтобы увидеть, сколько вещей делают бесполезные копии :D