Question

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?

Was it helpful?

Solution

[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 CComBSTRs.

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:

  1. _bstr_t is a reference counted smart-pointer wrapper over BSTR whereas CComBSTR does not provide any reference counting.
  2. _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;

OTHER TIPS

I think you can safely do this. The one thing that's prohibited is using containers of auto_ptr.

Since _bstr_t doesn't overload operator& you have no problems in using it in a stl container.

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));
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top