Podczas korzystania z modelu COM zazwyczaj korzystam z inteligentnych wskaźników ATL, takich jak ATL::CComPtr
i ATL::CComBSTR
, w celu zarządzania zasobami. Ale niektóre z wywoływanych przeze mnie metod używają parametrów wyjściowych do zwracania wskaźników do przydzielonego miejsca, które muszę zwolnić. Na przykład:Obsługa pamięci o wyjątkowych właściwościach z COM
WCHAR *pszName = nullptr;
if (SUCCEEDED(pShellItem->GetDisplayName(SIGDN_FILESYSPATH, &pszName))) {
DoSomething(pszName);
CoTaskMemFree(pszName);
}
Zauważ, że GetDisplayName
przydziela pamięć dla łańcucha i zwraca wskaźnik do niego za pośrednictwem parametru wyjściowego. Obowiązkiem osoby wywołującej jest zwolnienie tej pamięci za pomocą CoTaskMemFree
.
Jeśli DoSomething
zgłasza wyjątek, powyższy kod wycieknie. Chciałbym użyć jakiegoś inteligentnego wskaźnika dla pszName
, aby uniknąć takich przecieków, ale API bierze WCHAR**
, więc nie widzę, jak mogę przekazać cokolwiek innego niż adres niemądrego wskaźnika. Ponieważ nie jestem tym, który przydziela, nie mogę używać RAII.
I może użytkowania RRID czy mogę zrobić Deleter tak:
struct CoTaskMemDeleter {
void operator()(void *p) { ::CoTaskMemFree(p); }
};
a następnie natychmiast przypisać zwrócony wskaźnik do standardowej inteligentnego wskaźnika jak ten:
WCHAR *pszName = nullptr;
if (SUCCEEDED(pShellItem->GetDisplayName(SIGDN_FILESYSPATH, &pszName))) {
std::unique_ptr<WCHAR, CoTaskMemDeleter> guard(pszName);
DoSomething(pszName);
}
który działa , ale wydaje się być podatnym na błędy wprowadzenie dodatkowej zmiennej ochronnej. Na przykład to podejście pozostawia pszName
wskazując na zwolnioną pamięć, aby łatwo było z niej przypadkowo skorzystać.
Czy istnieje czyściejszy sposób użycia inteligentnego wskaźnika lub opakowania RAII dla pamięci przydzielonej serwerowi COM zwróconej przez parametr wyjściowy? Czy brakuje mi czegoś, co zapewnia ATL?
Co jest złego w uwalnianiu pamięci? Dla mnie nie wydaje się, by warto było robić cokolwiek innego. – evanmcdonnal
@evanmcdonnal: bezpieczeństwo wyjątków. –