Страницы

Поиск по вопросам

понедельник, 6 января 2020 г.

Необходимо ли освобождать интерфейс COM который был получен с помощью QueryInterface

#cpp #com #directx


Делаю обертку над некоторыми из объектов DirectX, дошло дело до копирования из другого
объекта DirectX т.е. преобразование из DirectX объекта в объект моего типа. У каждого
из таких объектов есть метод QueryInterface, далее, я запрашиваю интересующий меня
интерфейс у данного объекта и провожу некоторые действия с ним. По моему мнению другой
объект из которого был создан объект у которого я запросил интерфейс, кол-во ссылок
должно увеличиться, и для предотвращения утечек памяти, я должен вызвать Release для
объекта который я запросил.

Правильно ли так делать, и вообще нужно ли?

HRESULT result = ptr->QueryInterface(__uuidof(ID2D1HwndRenderTarget), reinterpret_cast(&m_render_target_));
if(result != S_OK)
{
    throw std::exception("Failed to QueryInterface from ID2D1SolidColorBrush");
}

result = m_render_target_->CreateSolidColorBrush(ptr->GetColor(), &m_solid_color_brush_ptr_);

if (result != S_OK)
{
    throw std::exception("Failed to CreateSolidColorBrush from ID2D1HwndRenderTarget");
}

m_solid_color_brush_ptr_->SetOpacity(ptr->GetOpacity());

D2D1_MATRIX_3X2_F matrix;
memset(&matrix, 0, sizeof matrix);
ptr->GetTransform(&matrix);
m_solid_color_brush_ptr_->SetTransform(matrix);


Для m_render_target_ локального поля, я должен вызвать Release в деструкторе, а в
обычном конструкторе добавить ссылку вызвав AddRef, т.к. в обычный конструктор передается
указатель на этот объект?
    


Ответы

Ответ 1



Да, вызов QueryInterface увеличивает внутренний счетчик ссылок объекта, поэтому у успешно полученного указателя следует вызвать Release. Однако делать это все руками не следует, благо это все уже реализовано в умных указателях, например WRL::ComPtr: ::Microsoft::WRL::ComPtr<::ID3D11Device> p_d3d_device{}; // создаем D3D устройство... ::Microsoft::WRL::ComPtr<::IDXGIDevice> p_dxgi_device{}; if(!SUCCEEDED(p_d3d_device.As(&p_dxgi_device))) // тут вызовется `QueryInterface` { /* обработка ошибки */ } // при выходе из области видимости у каждого указателя будет вызван `Release`

Ответ 2



Правило очень простое, AddRef и Release должны быть строго симметричны. И да, корректный QueryInterface в случае успеха, должен вызывать AddRef для объекта. Поэтому после завершения работы с вашими интерфейсами, вы должны вызвать Release и все. Офтоп. Второе исключение которое вы бросаете выглядит опасно, не забыли ли вы что m_render_target уже получен и нуждается в заботе.

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

Отправить комментарий