Функция C ++, возвращающая BSTR для функции, которая не может вызвать SysFreeString ()

Пожалуйста, потерпите меня, я некоторое время был программистом на C ++.

Мне нужно знать, если я делаю это неправильно. Это работает, но я подозреваю, что это вызывает утечку памяти. У меня есть такая функция:

_bstr_t WCH2BSTR(wchar_t* st)
{
    BSTR stres = SysAllocString(st);
    return (_bstr_t)stres;
}

Скажем, я должен был использовать такой результат:

wcout << WCH2BSTR(wCharArr) << " done." << endl;

Приведет ли это к утечке памяти или BSTR будет удален «сборщиком мусора», как в Java?

Если это утечка памяти, как я могу предотвратить ее, не теряя возможности сделать это как однострочник? Иногда результаты WCH2BSTR сохраняются в переменной BSTR и удаляются должным образом, но я хотел бы использовать ту же функцию для конкатенации wchar_t с BSTR в однострочном режиме.

Спасибо.


person Brian    schedule 08.03.2018    source источник
comment
в C ++ нет автоматической сборки мусора.   -  person Joseph D.    schedule 08.03.2018
comment
SysFreeString является необходимым требованием для использования SysAllocString, иначе вы правы, у вас утечка памяти.   -  person acraig5075    schedule 08.03.2018
comment
Во-первых, поскольку этот вопрос относится к Windows, а не к стандартному C ++, вы можете пометить вопрос для Windows или Microsoft (а не C ++), чтобы увеличить шансы на получение полезного ответа. Во-вторых, взгляните на MSDN, в частности на docs.microsoft.com/en-us/cpp/atl-mfc-shared/   -  person Peter    schedule 08.03.2018
comment
@codekaizer: есть автоматическая сборка мусора в C ++. Он отличается от сборки мусора Java или .NET тем, что является детерминированным. Помните, что в C ++ автоматическая продолжительность хранения не зря называется автоматической.   -  person IInspectable    schedule 08.03.2018


Ответы (1)


У вас утечка памяти. Но это тонко:

Эта строка:

BSTR stres = SysAllocString(st);

Выделяет BSTR, как вы ожидаете.

Однако оператор возврата:

return (_bstr_t)stres;

Запускает вызов конструктора _bstr_t(const wchar_t*), а не конструктора, который, в свою очередь, выделяет другой BSTR через SysAllocString. Итак, вы утекли строку из первоначального вызова.

Это, вероятно, ближе к тому, что вы хотите:

_bstr_t WCH2BSTR(const wchar_t* st)
{
    return _bstr_t(str);
}

Конструктор _bstr_t сделает за вас SysAllocString. Деструктор _bstr_t сделает за вас SysFreeString.

Но ...

Будьте осторожны, говоря это:

BSTR bstr = WCH2BSTR(L"Foo");

Потому что это будет компилироваться! Но после присвоения необработанному BSTR деструктор _bstr_t, возвращенный вспомогательной функцией, будет вызван и освободит уже возвращенный указатель.

Что вы действительно хотите сделать, так это просто полностью отказаться от вспомогательной функции и явно указать это в своем коде:

_bstr_t bstr = L"Foo";

Когда _bstr_t выходит за пределы области видимости, то же самое происходит и с лежащим в его основе BSTR.

person selbie    schedule 08.03.2018
comment
Боковое примечание. В результате написания этого, я думаю, я только что обнаружил, почему std::string не позволяет явно преобразовывать себя в const char*, а вместо этого заставляет вызывающих абонентов использовать метод .c_str(). Это потому, что в коде могут появиться подобные ошибки. - person selbie; 08.03.2018
comment
Тело функции может быть return st; - person M.M; 08.03.2018
comment
Обратите внимание, что _bstr_t имеет перегруженный конструктор, который принимает существующие BSTR и bool, чтобы указать, копируется ли BSTR или нет. Итак, если вы позвонили BSTR stres = SysAllocString(st);, вы можете использовать return _bstr_t(stres, false);, чтобы стать владельцем BSTR и избежать утечки. Но вы правы, что return _bstr_t(st); лучше. - person Remy Lebeau; 08.03.2018
comment
Что ж, вам понадобится std :: wstring вместо std :: string, и да, вы можете использовать его и вызвать .c_str (). Но вы также можете напрямую использовать исходную строку указателя wchar_t с помощью std :: wcout. Я также думаю, что простое использование исходной строки wchar_t напрямую - лучший способ удовлетворить ваше утверждение, что вы действительно хотите просто полностью избежать вспомогательной функции. Смотрите мой ответ. - person Dan Korn; 09.03.2018