Использование _bstr_t для передачи параметра типа BSTR * в функцию - PullRequest
9 голосов
/ 03 декабря 2010

Как правильно это сделать:

_bstr_t description;
errorInfo->GetDescription( &description.GetBSTR() );

или

_bstr_t description;
errorInfo->GetDescription( description.GetAddress() );

Где IError:GetDescription определяется как:

HRESULT GetDescription (BSTR *pbstrDescription);

Я знаю, я мог бы легко сделать это:

BSTR description= SysAllocString (L"Whateva"));
errorInfo->GetDescription (&description);
SysFreeString (description);

Спасибо

Ответы [ 3 ]

9 голосов
/ 03 декабря 2010

BSTR подсчитывает ссылки, я серьезно сомневаюсь, что это будет работать правильно, если вы используете GetAddress (). К сожалению, исходный код не доступен, чтобы перепроверить это. Я всегда делал это так:

BSTR temp = 0;
HRESULT hr = p->GetDescription(&temp);
if (SUCCEEDED(hr)) {
    _bstr_t wrap(temp, FALSE);
    // etc..
}
5 голосов
/ 03 декабря 2010

Чтобы ответить на вопрос @ Ганса - правильный способ построения _bstr_t зависит от того, вернет ли GetDescription вам BSTR, который у вас есть, или тот, который ссылается на память, которую вам не нужно освобождать.

Цель здесь - минимизировать количество копий, а также избегать любых ручных вызовов SysFreeString для возвращаемых данных.Я бы изменил код, как показано, чтобы уточнить это:

BSTR temp = 0;
HRESULT hr = p->GetDescription(&temp);
if (SUCCEEDED(hr)) {
    _bstr_t wrap(temp, false);    // do not copy returned BSTR, which
                                  // will be freed when wrap goes out of scope.
                                  // Use true if you want a copy.
    // etc..
}
2 голосов
/ 19 июля 2016

поздний ответ, который может не относиться к более ранним (или более поздним) версиям Visual Studio;однако VS 12.0 имеет встроенную реализацию _bstr_t, и, очевидно, внутренний экземпляр Data_t создается с m_RefCount, равным 1, при вызове GetBSTR() для девственной _bstr_t.Таким образом, жизненный цикл _bstr_t в вашем первом примере выглядит нормально:

_bstr_t description;
errorInfo->GetDescription( &description.GetBSTR() );

Но если _bstr_t загрязнен, существующий внутренний указатель m_wstr будет перезаписан, что приведет к утечке предыдущей памяти, на которую он ссылался.

Используя следующее operator&, можно использовать грязный _bstr_t, учитывая, что он сначала очищается с помощью Assign(nullptr).Перегрузка также обеспечивает удобство использования оператора адреса вместо GetBSTR();

BSTR *operator&(_bstr_t &b) {
    b.Assign(nullptr);
    return &b.GetBSTR();
}

Итак, ваш первый пример может выглядеть следующим образом:

_bstr_t description(L"naughty");
errorInfo->GetDescription(&description);

Эта оценка былана основе comutil.h от VS 12.0.

...