У меня есть цепочка продолжения с использованием лямбда-выражений, где одна задача назначает переменную, а следующая задача считывается из этой переменной. Microsoft suggests using a shared_ptr
to wrap the variable even when the variable is a reference-counted handle (^). Не обработал ли счетчик отсчета счетчик ссылок при захвате значением значением лямбда? Почему тогда необходимо обернуть обработанный ссылкой счетчик с помощью shared_ptr
?Нужны ли общие указатели в цепях продолжения?
ответ
документация становится ясно, что дела, они обеспокоены являются те, где
одна задача в продолжении цепи присваивает переменной, и другая задача читает эту переменную
(Акцент мой.) Это не вопрос объекта life life, а вопрос об объекте identity.
Возьмите этот пример из Hilo project, обращая особое внимание на переменную decoder
(который является 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
быть определены как BitmapDecoder^
, установите его в nullptr
, а затем присвоить ему значение в пределах второго продолжения, это изменение не будет распространяться на последующие продолжений, потому что изменение не может отражаться обратно к исходной ручке (лямбда сделала копию дескриптора, по существу копируя адрес памяти 0x00000000).
Для обновления исходной версии (и последующих ссылок) вам потребуется дополнительное косвенное направление (например, BitmapDecoder^*
). A shared_ptr<BitmapDecoder^>
- одно из таких направлений и полезно, поскольку вам не нужно управлять временем жизни указателя, в отличие от необработанного указателя, поэтому рекомендуется в документации.
Есть и другие случаи, когда захват Object^
было бы достаточно, если я создал TextBlock^
вне моего продолжения и установить некоторые свойства этого в первом продолжении и прочитать некоторые другие свойства в последующем продолжении. В этом случае все дескрипторы относятся к одному и тому же базовому объекту, и никакое продолжение не пытается переписать личность самого объекта. (Однако, как первоначально упоминалось, это не тот случай, о котором идет речь в документации.)