2017-06-01 81 views
4

此问题中的代码使用Either<>实现此处找到:https://github.com/LoopPerfect/neither。要清楚,我怀疑这是特定图书馆的问题,否则我会在那里创建一个问题。std :: future <既不是:: int,std :: string >>分段错误

下面的代码片段按预期工作:

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之前返回false,但valid返回true。

有什么我在这里失踪?

回答

11

有什么我在这里失踪?

该库没有正确实施。专门为这个问题的目的,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); 
+0

你能再解释一下吗?内部调用是在调用复制构造函数之前调用'right( const&)',它应该构造'rightValue'。 –

+0

@DavidFreitag'e'构造正确,但'this'不是。星号调用'std :: string :: operator =(std :: string const&)',它需要'std :: string'存在 - 但我们没有'std :: string',我们有未初始化的内存。 – Barry

+0

好吧,我明白了。源'e.rightValue'被构造,但目的地'this-> rightValue'未初始化。那么你认为解决这个问题的是什么?它不完全像你可以默认构建'leftValue'和'rightValue'。 –

相关问题