Reputation: 3214
I have an ATL COM component method which takes a BSTR as an in parameter. I need to add each call to this method in an array. I can't use a SAFEARRAY as that is fixed size so I was thinking that std::vector would be the easiest choice. Of course I will need to call SysAllocString for each addition to the vector. This means that SysFreeString needs to be called for each entry before the vector is destroyed.
I was looking for an easier/cleaner solution and thought of declaring the vector as vector<_bstr_t> which would include automatic cleanup. However, something in the back of my mind is raising the alarm at holding what is effectively a smart pointer in a standard container. Are my worries justified or can I safely do this? If not are there any other nicer solutions?
Upvotes: 2
Views: 2658
Reputation: 66922
BSTR
is a C struct that you have to call SysAllocString
and SysFreeString
on. _bstr_t
is a C++ type that calls SysAllocString
and SysFreeString
for you, and is totally 100% safe in a std::vector
. You do not have to and should not call SysAllocString
nor SysFreeString
when dealing with _bstr_t
objects.
If you are instead dealing with the C struct BSTR
objects:
(1) You can safely store smart pointers in containers, except for auto_ptr
, which simply pretends to be smart.
(2) A vector
can store _bstr_t
, except it doesnt understand SysFreeString
, and you will have to call that manually. Just like you'd have to delete
on a raw pointer, because _bstr_t
is not a smart pointer.
(3) a std::unique_ptr<BSTR, HRESULT (*)(BSTR)>(mybstr, SysFreeAlloc)
is a smart pointer that will safely and magically do everything for you, including completely safe storage in a vector, with no overhead. However, that's ugly to write, so most people use:
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));
Upvotes: 0
Reputation: 111150
[regarding
vector< _bstr_t >
] Are my worries justified or can I safely do this?
Yes. While you can safely use _bstr_t
bear in mind that not only is it a smart pointer, but it is a reference counted smart pointer. Which means additional cost.
If not are there any other nicer solutions?
I would typically use a CComBSTR
instead of BSTR
or _bstr_t
. If you need reference counting then you have to fall back on _bstr_t
. E.g: If you're also using ATL, you will probably only ever want CComBSTR
s.
The CComBSTR class is a wrapper for BSTRs, which are length-prefixed strings. The length is stored as an integer at the memory location preceding the data in the string.
A BSTR is null-terminated after the last counted character but may also contain null characters embedded within the string. The string length is determined by the character count, not the first null character.
So, before making a choice do consider the following:
_bstr_t
is a reference counted smart-pointer wrapper over BSTR
whereas CComBSTR
does not provide any reference counting._bstr_t
does not redefine the address-of operator and can thus be safely stored in a STL container. With CComBSTR
you will need to use CAdapt
.About the CAdapt
object:
CAdapt is a simple template used to wrap classes that redefine the address-of operator (operator &) to return something other than the address of the object. Examples of such classes include ATL's CComBSTR, CComPtr, and CComQIPtr classes, and the compiler COM support class, _com_ptr_t. These classes all redefine the address-of operator to return the address of one of their data members (a BSTR in the case of CComBSTR, and an interface pointer in the case of the other classes).
And then you can use:
typedef std::vector< CAdapt< CComBSTR > > MyString;
Upvotes: 4
Reputation: 2305
Since _bstr_t doesn't overload operator& you have no problems in using it in a stl container.
Upvotes: 1
Reputation: 52539
I think you can safely do this. The one thing that's prohibited is using containers of auto_ptr
.
Upvotes: 1