CComBSTR
— это оболочка RAII для необработанных BSTR
строк.
В первом фрагменте кода, который вы разместили:
outDomainPath = bstrDomainPath.Detach();
вы вызываете CComBSTR::Detach
, который освобождает право собственности обернутой строки BSTR
и передает это владение кому-то другому.
В вашем случае кто-то еще является объектом std::wstring
(на который ссылается outDomainPath
), который не обертка RAII вокруг BSTR
s.
Теперь учтите, что с точки зрения системы типов C++ BSTR
в основном представляет собой wchar_t*
. Более того, std::wstring
реализует перегрузки конструктора и оператора присваивания, которые принимают const wchar_t*
в качестве входных данных, предполагая, что эти необработанные указатели wchar_t
являются строками с нулевым завершением в стиле C в стиле C. Таким образом, вы можете создавать std::wstring
объектов из необработанных строк в стиле C.
Проблема в том, что когда вы вызываете CComBSTR::Detach
, необработанное право владения BSTR
передается вызывающей стороне, которая отвечает за надлежащее освобождение строки BSTR
.
Но в вашем случае вы создаете объект wstring
из wchar_t*
(BSTR
), возвращенного CComBSTR::Detach
, осиротевшим возвращенную строку BSTR
.
Фактически, кто будет нести ответственность за надлежащий выпуск BSTR
, вызывая SysFreeString
? Деструктор std::wstring
этого не сделает.
Итак, в этом случае вы пропускаете BSTR
, возвращаемый CComBSTR::Detach
.
С другой стороны, во втором фрагменте кода:
outDomainPath = bstrDomainPath;//removed detach
что происходит, так это то, что компилятор неявно вызывает CComBSTR::operator BSTR
, что в основном дает вызывающему доступ к BSTR
, обернутому внутри CComBSTR
. Обратите внимание, что в этом случае не происходит передачи права собственности: вы просто наблюдаете BSTR
, который по-прежнему принадлежит RAII-оболочке CComBSTR
.
std::wstring
имеет конструктор и перегрузку op= для создания wstring
объектов из необработанных const wchar_t*
строк в стиле C, заканчивающихся NUL. BSTR
в основном представляет собой wchar_t*
с точки зрения системы типов C++, поэтому, если ваш BSTR
содержит строку, заканчивающуюся NUL (без встроенных NUL внутри), эта строка кода будет дублировать BSTR
строку, скопировав ее в объект std::wstring
.
Затем, в конце вашей функции GetPath
, локальный объект CComBSTR bstrDomainPath
выйдет из области видимости, деструктор CComBSTR
будет автоматически вызван компилятором C++, а SysFreeString
будет вызван для правильного освобождения обернутого BSTR
.
В этом случае у вас нет утечки BSTR
.
Обратите внимание, что этот код работает, если у вас нет встроенных значений NUL в BSTR
. В случае встроенных значений NUL будет скопирована только первая подстрока, поскольку конструктор wstring
, принимающий const wchar_t*
в качестве входных данных, остановится на первом значении NUL.
Кроме того, я рекомендую вам прочитать этот интересный пост в блоге:
Руководство Эрика Липперта по семантике BSTR
person
Mr.C64
schedule
06.02.2018