std::future<neither::Either<int, std::string>> 分段错误

std::future<neither::Either<int, std::string>> segmentation fault

此问题中的代码使用此处的 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 可能会产生一个段错误,因为你已经调用了它两次,在这种情况下 std::future::valid 会在调用 get 之前 return false,但是 valid return是真的。

我在这里遗漏了什么吗?

Is there something I'm missing here?

库未正确实现。专门针对此问题的目的,copy constructor 是错误的:

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);