0

我有一个使用 lambda 表达式的延续链,其中一个任务分配给一个变量,下一个任务从该变量中读取。Microsoft 建议使用 ashared_ptr来包装变量,即使变量是引用计数句柄 (^) 也是如此当 lambda 表达式按值捕获时,引用计数句柄不会增加其引用计数吗?那么为什么有必要用 包装一个引用计数句柄shared_ptr

4

1 回答 1

3

文档清楚地表明,他们关注的案例是

延续链中的一个任务分配给一个变量,另一个任务读取该变量

(重点是我的。)这不是对象生命周期的问题,而是对象身份的问题。

Hilo 项目中的这个例子为例,密切关注decoder变量(即 a shared_ptr<BitmapDecoder^>):

task<InMemoryRandomAccessStream^> ThumbnailGenerator::CreateThumbnailFromPictureFileAsync(
    StorageFile^ sourceFile, 
    unsigned int thumbSize)
{
    (void)thumbSize; // Unused parameter
    auto decoder = make_shared<BitmapDecoder^>(nullptr);
    auto pixelProvider = make_shared<PixelDataProvider^>(nullptr);
    auto resizedImageStream = ref new InMemoryRandomAccessStream();
    auto createThumbnail = create_task(
        sourceFile->GetThumbnailAsync(
        ThumbnailMode::PicturesView, 
        ThumbnailSize));

    return createThumbnail.then([](StorageItemThumbnail^ thumbnail)
    {
        IRandomAccessStream^ imageFileStream = 
            static_cast<IRandomAccessStream^>(thumbnail);

        return BitmapDecoder::CreateAsync(imageFileStream);

    }).then([decoder](BitmapDecoder^ createdDecoder)
    {
        (*decoder) = createdDecoder;
        return createdDecoder->GetPixelDataAsync( 
            BitmapPixelFormat::Rgba8,
            BitmapAlphaMode::Straight,
            ref new BitmapTransform(),
            ExifOrientationMode::IgnoreExifOrientation,
            ColorManagementMode::ColorManageToSRgb);

    }).then([pixelProvider, resizedImageStream](PixelDataProvider^ provider)
    {
        (*pixelProvider) = provider;
        return BitmapEncoder::CreateAsync(
            BitmapEncoder::JpegEncoderId, 
            resizedImageStream);

    }).then([pixelProvider, decoder](BitmapEncoder^ createdEncoder)
    {
        createdEncoder->SetPixelData(BitmapPixelFormat::Rgba8,
            BitmapAlphaMode::Straight,
            (*decoder)->PixelWidth,
            (*decoder)->PixelHeight,
            (*decoder)->DpiX,
            (*decoder)->DpiY,
            (*pixelProvider)->DetachPixelData());
        return createdEncoder->FlushAsync();

    }).then([resizedImageStream]
    {
        resizedImageStream->Seek(0);
        return resizedImageStream;
    });
}

decoder变量首先在延续之外定义,因为在多个延续中需要它。此时,它的值为空。它是在第二个延续中获得和设置的,并且该对象(PixelWidth等)的属性在第四个延续中使用。

如果您将decoder其定义为 a BitmapDecoder^,将其设置为nullptr,然后在第二个延续中为其分配一个值,则该更改不会传播到后续延续,因为更改无法反映回初始句柄(lambda 已复制句柄,本质上是复制内存地址 0x00000000)。

为了更新原始版本(和后续引用),您需要一个额外的间接(例如 a BitmapDecoder^*)。Ashared_ptr<BitmapDecoder^>是一种这样的间接方式,它很有用,因为您不需要像使用原始指针那样管理指针的生命周期,这就是为什么在文档中推荐它的原因。

在其他情况下,捕获一个Object^就足够了,例如,如果我在TextBlock^我的延续中创建了一个外部并在第一个延续中设置它的一些属性,并在后续延续中读取一些其他属性。在这种情况下,所有句柄都指向同一个底层对象,并且没有继续尝试覆盖对象本身的标识。(但是,正如最初提到的,这不是文档所指的用例。)

于 2015-02-04T00:14:22.107 回答