我有一个ATL COM组件方法,它将BSTR作为in参数。我需要在数组中添加对此方法的每次调用。我不能使用SAFEARRAY因为它是固定大小所以我认为std :: vector将是最简单的选择。当然,我需要为向量的每次添加调用SysAllocString。这意味着在向量被销毁之前需要为每个条目调用SysFreeString。
我一直在寻找一种更简单/更清洁的解决方案,并考虑将矢量声明为矢量< _bstr_t>其中包括自动清理。然而,在我的脑海中,有些事情是在标准容器中保存有效的智能指针时引发警报。我的担忧是否合理,或者我可以安全地做到这一点吗?如果没有,还有其他更好的解决方案吗?
答案 0 :(得分:3)
[关于
vector< _bstr_t >
]我的担忧是否合理,或者我可以安全地做到这一点吗?
是。虽然可以安全地使用_bstr_t
,但请注意,它不仅是智能指针,而且是引用计数智能指针。这意味着额外的费用。
如果没有其他更好的解决方案?
我通常使用CComBSTR
代替BSTR
或_bstr_t
。如果您需要引用计数,那么您必须回到_bstr_t
。例如:如果你也在使用ATL,你可能只需要CComBSTR
s。
CComBSTR类是BSTR的包装器,它是长度为前缀的字符串。长度存储为整数,位于字符串中数据之前的内存位置。
BSTR在最后计算的字符之后以空值终止,但也可能包含嵌入字符串中的空字符。字符串长度由字符数决定,而不是第一个空字符。
因此,在做出选择之前,请考虑以下事项:
_bstr_t
是BSTR
上的引用计数智能指针包装器,而CComBSTR
不提供任何引用计数。_bstr_t
不重新定义地址操作符,因此可以安全地存储在STL容器中。使用CComBSTR
,您需要使用CAdapt
。关于CAdapt
对象:
CAdapt是一个简单的模板,用于包装重新定义地址运算符(运算符&amp;)的类,以返回除对象地址之外的其他内容。此类的示例包括ATL的CComBSTR,CComPtr和CComQIPtr类,以及编译器COM支持类_com_ptr_t。这些类都重新定义了address-of运算符,以返回其中一个数据成员的地址(在CComBSTR的情况下为BSTR,在其他类的情况下为接口指针)。
然后你可以使用:
typedef std::vector< CAdapt< CComBSTR > > MyString;
答案 1 :(得分:1)
我认为你可以安全地做到这一点。禁止的一件事是使用auto_ptr
的容器。
答案 2 :(得分:1)
由于_bstr_t不会使运算符&amp;在stl容器中使用它没有问题。
答案 3 :(得分:0)
BSTR
是一个C结构,您必须调用SysAllocString
和SysFreeString
。 _bstr_t
是一种C ++类型,可以为您调用SysAllocString
和SysFreeString
,并且在std::vector
中完全100%安全。在处理SysAllocString
个对象时,您不必也不应该致电SysFreeString
或_bstr_t
。
如果您正在处理C结构BSTR
对象:
(1)您可以安全地将智能指针存储在容器中,auto_ptr
除外,它只是假装聪明。
(2)vector
可以存储_bstr_t
,但不理解SysFreeString
,您必须手动调用它。就像你必须在原始指针上delete
一样,因为_bstr_t
不是智能指针。
(3)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));