The code in this question uses the Either<>
implementation found here: https://github.com/LoopPerfect/neither. To be clear, I doubt that this is a problem with this specific library, otherwise I would have created an issue there.
The following snippet works as expected:
std::future<std::string> f = std::async(std::launch::async, []()
{
return "test";
}
std::cout << f.get() << std::endl;
And the following generates a segmentation fault:
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;
Returning left(-1)
works, as does neither::Either<int, int>
for both left()
and right()
. I know that std::future::get
might generate a segfault is that you've called it twice, in which case std::future::valid
will return false just prior to calling get
, but valid
returns true.
Is there something I'm missing here?
Is there something I'm missing here?
The library isn't properly implemented. Specifically for the purposes of this question, the copy constructor is wrong:
constexpr Either( Either<L, R> const& e )
: isLeft(e.isLeft) {
if(isLeft) {
leftValue = e.leftValue;
} else {
rightValue = e.rightValue; // (*)
}
}
We can't assign to this->rightValue
there, there isn't a std::string
in existence at that spot - we have uninitialized memory.
A correct copy constructor would be:
Either(Either<L, R> const& e)
: isLeft(e.isLeft)
{
if(isLeft) {
new (&leftValue) L(e.leftValue);
} else {
new (&rightValue) R(e.rightValue);
}
}
or, since we're writing generic library code that could be used by all sorts of evil types, you'll want:
::new (static_cast<void*>(std::addressof(leftValue))) L(e.leftValue);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With