Код в этом вопросе использует Either<>
Реализация найдена здесь: https://github.com/LoopPerfect/neither. Чтобы было ясно, я сомневаюсь, что это проблема с этой конкретной библиотекой, иначе я бы создал проблему там.
Следующий фрагмент работает как положено:
std::future<std::string> f = std::async(std::launch::async, []()
{
return "test";
}
std::cout << f.get() << std::endl;
И следующее генерирует ошибку сегментации:
std::future<neither::Either<int, std::string>> f = std::async(std::launch::async, []()
{
return neither::Either<int, std::string>(neither::right(std::string("test")));
});
neither::Either<int, std::string> v = f.get(); // Segmentation fault
std::cout << v.right().value << std::endl;
возврате left(-1)
работает, как и neither::Either<int, int>
для обоих left()
а также right()
, я знаю это std::future::get
может генерировать segfault, что вы вызвали его дважды, в этом случае std::future::valid
вернет false перед вызовом get
, но valid
возвращает истину.
Есть что-то, чего я здесь не хватает?
Есть что-то, чего я здесь не хватает?
Библиотека не реализована должным образом. Специально для целей этого вопроса конструктор копирования неправильно:
constexpr Either( Either<L, R> const& e )
: isLeft(e.isLeft) {
if(isLeft) {
leftValue = e.leftValue;
} else {
rightValue = e.rightValue; // (*)
}
}
Мы не можем назначить this->rightValue
там нет std::string
существует в этом месте — у нас неинициализированная память.
Правильный конструктор копирования будет:
Either(Either<L, R> const& e)
: isLeft(e.isLeft)
{
if(isLeft) {
new (&leftValue) L(e.leftValue);
} else {
new (&rightValue) R(e.rightValue);
}
}
или, поскольку мы пишем общий библиотечный код, который может использоваться всеми видами злых типов, вам понадобится:
::new (static_cast<void*>(std::addressof(leftValue))) L(e.leftValue);
Других решений пока нет …