2017-06-01 110 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'。 –

相關問題