IVectorView файла хранилища становится нулевым после OpenReadAsync в цикле (возможная ошибка winrt)

#uwp #c -winrt

#uwp #c -winrt

Вопрос:

Я создаю класс среды выполнения внутри шаблона проекта BlankApp, который открывает IVectorView<StorageFile> , который он получает по ссылке в качестве параметра. Затем он перебирает вектор для чтения из файлов. Однако, когда я пытаюсь использовать вектор после вызова для чтения, он выдает нарушение доступа для чтения.

Причина, по которой я думаю, что это ошибка, заключается в том, что это происходит только при компиляции с использованием конфигурации x64 проекта BlankApp. В x86 исключение не выдается.

Это довольно легко воспроизвести, поэтому было бы неплохо, если бы кто-то еще мог подтвердить, происходит ли это с ними.

 //test_class.idl

[bindable]
[default_interface]
runtimeclass test_class
{
    test_class();

    Windows.Foundation.IAsyncAction read_files(Windows.Foundation.Collections.IVectorView<Windows.Storage.StorageFile> files);
}
  
 //test_class.cpp
Windows::Foundation::IAsyncAction test_class::read_files(Windows::Foundation::Collections::IVectorView<Windows::Storage::StorageFile> constamp; files)
{
    for (autoamp; file : files)
    {
        auto res = files;
        auto stream = co_await file.OpenReadAsync();
        auto res2 = files; // read access violation. this->**m_ptr** was 0xFFFFFFFFFFFFFFFF.
    }

    co_return;
}
  
 //MainPage.cpp
Windows::Foundation::IAsyncAction MainPage::onclick_button(Windows::Foundation::IInspectable const amp; sender, Windows::UI::Xaml::RoutedEventArgs const amp; args)
{
    BlankApp1::test_class m_test_class = winrt::make<BlankApp1::implementation::test_class>();

    Windows::Storage::Pickers::FileOpenPicker picker;
    picker.FileTypeFilter().Append(L".bmp");

    Windows::Foundation::Collections::IVectorView<Windows::Storage::StorageFile> files = co_await picker.PickMultipleFilesAsync();

    co_await m_test_class.read_files(files);
}
  

Ответ №1:

Это происходит потому, что вы передаете аргумент по ссылке на асинхронный метод. Во время co_await вызывающая функция ( onclick_button ), возможно, очистила объекты, на которые ссылается ваша ссылка, что в основном приводит к зависанию ссылки. Чтобы избежать этого, ваши сопрограммы должны принимать параметры по значению, а не по ссылке.

Смотрите следующий раздел для получения более подробной информации:https://learn.microsoft.com/en-us/windows/uwp/cpp-and-winrt-apis/concurrency#parameter-passing

Комментарии:

1. Если я правильно понимаю, прогнозируемые типы являются моральным эквивалентом std::shared_ptr . В этом случае есть 2 непосредственных последствия, которые явно не указаны в документации: 1 Передача по значению довольно дешевая (копия указателя плюс бухгалтерия). 2 Передача по значению логически равносильна передаче по ссылке; новый экземпляр реализации не создается, и копия спроектированного типа по-прежнему ссылается на исходную реализацию. Я прав, или моя ментальная модель нарушена?

2. Это примерно правильно. Передача по значению не требует ничего сумасшедшего, такого как выделение кучи. Но «бухгалтерия» по-прежнему требует явно нетривиальных затрат на производительность. Как addref, так и release связаны с вызовом виртуальной функции, и счетчик ссылок обычно блокируется. Итак, передавайте по const ref, когда это возможно, но также не теряйте слишком много времени ожидания, когда требуется передача по значению.