2013-08-24 33 views
0

我正在用C++/CX編寫Windows手機應用程序。的函數試圖輸入數組複製到輸出數組異步:修改捕獲的數組C++ 11 lambda函數

IAsyncAction CopyAsync(const Platform::Array<byte, 1>^ input, Platform::WriteOnlyArray<byte, 1>^ output) 
{ 
    byte *inputData = input->Data; 
    byte *outputData = output->Data; 
    int byteCount = input->Length; 
    // if I put it here, there is no error 
    //memcpy_s(outputData, byteCount, inputData, byteCount); 
    return concurrency::create_async([&]() -> void { 
     memcpy_s(outputData, byteCount, inputData, byteCount); // access violation exception 
     return; 
    }); 
} 

該功能編譯,但不能正確運行,併產生一個「訪問衝突異常」。我如何修改輸出數組中的值?

+1

'output-> Data'的值在函數頂部捕獲並在lambda內使用它之間發生變化。 –

回答

1

這是未定義的行爲:當您在lambda表達式中使用3個捕獲的(引用)變量inputData/outputData/byteCount時,您已經從CopyAsync返回並且堆棧已被刪除。

這真的是一個問題,如果你從一個函數(我們知道它是邪惡的)返回一個局部變量的引用,除了這裏的引用被隱藏在lambda中,所以看起來有點難以乍看。


如果肯定inputoutput不會改變,仍然會調用CopyAsync的時刻,剎那之間可達運行異步操作,你可以通過值而不是捕捉你的變量引用:

return concurrency::create_async([=]() -> void { 
//        ^here 
    memcpy_s(outputData, byteCount, inputData, byteCount); 
    return; 
}); 

因爲他們是唯一指針(和int),你會不會複製指向的數據,只有指針本身。


或者你可以捕捉inputoutput的價值:因爲他們是垃圾收集指針,這將至少確保對象仍然由時間可達運行拉姆達:

return concurrency::create_async([=]() -> void { 
    memcpy_s(output->Data, input->Length, input->Data, input->Length); 
    return; 
}); 

我比較喜歡第二種解決方案,它比第一種解決方案提供更多的保證(即對象可達性)。

+0

我認爲你的理由是正確的,但你的兩個建議並沒有解決我的問題,我仍然有一個訪問衝突異常。我認爲問題在於該函數僅捕獲指向數據的指針,而不捕獲它自身的數據,即使它們被值捕獲。如何將整個數組捕獲到lambda函數中? –

+1

我相信如果你在調用'CopyAsync'後不手動刪除或修改你的'輸入/輸出'對象,我相信第二個*應該*工作(儘管我對MS''怪異的GC指針不太熟悉) 。你是否想在'CopyAsync'之後重用這些對象?關於通過值捕獲數組,它可能會工作,但是然後你會同步地創建一個副本(捕獲),然後另一個異步(lambda),這沒有多大意義:你也可以同步拷貝一次併爲所有。 – syam