2012-06-19 2 views
2

У меня есть компонент компонента ATL COM, который принимает BSTR как параметр in. Мне нужно добавить каждый вызов этого метода в массив. Я не могу использовать SAFEARRAY, поскольку это фиксированный размер, поэтому я думал, что std :: vector будет самым простым выбором. Конечно, мне нужно будет вызвать SysAllocString для каждого добавления к вектору. Это означает, что SysFreeString нужно вызывать для каждой записи до того, как вектор будет уничтожен.Сохранить BSTR в std :: vector?

Я искал более легкое/более чистое решение и думал об объявлении вектора как вектора < _bstr_t> который включал бы автоматическую очистку. Тем не менее, что-то в глубине моего сознания поднимает тревогу, удерживая то, что эффективно является умным указателем в стандартном контейнере. Оправдываются ли мои опасения или могу ли я сделать это безопасно? Если нет других хороших решений?

ответ

3

[относительно vector<_bstr_t>] Оправданы ли мои опасения, или я могу спокойно это сделать?

Да. В то время как вы можете безопасно использовать _bstr_t помните, что это не только умный указатель, но это ссылка посчитана умный указатель. Это означает дополнительную стоимость.

Если нет других полезных решений?

Я обычно использую CComBSTR вместо BSTR или _bstr_t. Если вам нужен подсчет ссылок, тогда вы должны вернуться на _bstr_t. Например: если вы также используете ATL, вам, вероятно, понадобится только CComBSTR.

Класс CComBSTR является оберткой для BSTR, которые являются строками с префиксом длины. Длина сохраняется как целое число в ячейке памяти, предшествующей данным в строке.

BSTR заканчивается нулем после последнего подсчитанного символа, но может также содержать нулевые символы, встроенные в строку. Длина строки определяется числом символов, а не первым нулевым символом.

Таким образом, прежде чем сделать выбор действительно необходимо учитывать следующее:

  1. _bstr_t является подсчет ссылок смарт-указатель обертка над BSTRCComBSTRа не обеспечить любой подсчет ссылок.
  2. _bstr_tне переопределяет адрес-оператора и поэтому может быть безопасно сохранен в контейнере STL. С CComBSTR вам нужно будет использовать CAdapt.

О CAdapt объекта:

CAdapt простой шаблон используется, чтобы обернуть классы, которые переопределяют адрес-оператора (оператора &), чтобы вернуть что-то другое, чем адрес объекта. Примеры таких классов включают классы CComBSTR, CComPtr и CComQIPtr ATL, а также класс поддержки COM компилятора _com_ptr_t. Эти классы переопределяют адрес оператора для возврата адреса одного из своих членов данных (BSTR в случае CComBSTR и указателя интерфейса в случае других классов).

И тогда вы можете использовать:

typedef std::vector< CAdapt<CComBSTR> > MyString; 
1

Я думаю, вы можете смело сделать это. Единственное, что запрещено, это использование контейнеров auto_ptr.

+0

Но не _bstr_t только тип смарт-указатель? Или конкретно, что вы не должны ставить auto_ptr? Если да, почему именно это вы не должны ставить auto_ptr? Я прочитал это в какой-то момент, но я не могу вспомнить, почему это было сейчас. – Jonnster

+1

auto_ptr имеет «странную» семантику копирования, но для контейнеров std требуется несколько стандартная семантика копирования и назначения. У ссылок подсчета интеллектуальных указателей обычно есть такая семантика. – ltjax

+0

aalways предпочитают unique_ptr для shared_ptr –

1

Поскольку _bstr_t не перегружает оператора &, у вас нет проблем с его использованием в контейнере stl.

0

BSTR - это C структура, которую вы должны позвонить SysAllocString и SysFreeString. _bstr_t - это тип C++, который вызывает SysAllocString и SysFreeString для вас, и абсолютно безопасен на 100% в std::vector. Вам не нужно и не следует звонить SysAllocString или SysFreeString при работе с _bstr_t объектами.

Если вы вместо того, чтобы дело с C структуры BSTR объектов:
(1) Вы можете безопасно хранить смарт-указатели в контейнерах, для auto_ptr, который просто делает вид, чтобы быть умным исключением.
(2) A vector может хранить _bstr_t, кроме этого не понимает SysFreeString, и вам придется называть это вручную. Так же, как вы должны были бы delete на необработанном указателе, потому что _bstr_t is не умный указатель.
(3) a std::unique_ptr<BSTR, HRESULT (*)(BSTR)>(mybstr, SysFreeAlloc) - это умный указатель, который безопасно и волшебным образом сделает все для вас, включая полностью безопасное хранение в векторе, без накладных расходов. Тем не менее, это некрасиво писать, так что большинство людей используют:

template<class T, class F> 
std::unique_ptr<T, F> make_unique(T t, F f) 
{return std::unique_ptr<T,F>(std::move(t), std::move(f));} 

typedef decltype(make_unique(declval<BSTR>(), SysFreeAlloc)) bstr_ptr; 
std::vector<bstr_ptr> container; 
container.push_back(make_unique(mybstr, SysFreeAlloc)); 
+0

@Jonnster: Отредактировал свой ответ, теперь я понимаю разницу между '_bstr_t' и' BSTR'>. < –

Смежные вопросы