【问题标题】:Is there a way to write a BSTR literal?有没有办法写一个 BSTR 文字?
【发布时间】:2015-03-11 05:07:26
【问题描述】:

当调用一个需要 BSTR 的函数时,最好能够编写如下内容:

iFoo->function( bs"HELLO" );

但是我知道的唯一解决方法是使用调用 SysAllocString 等的包装器,例如:

iFoo->function( WideString(L"HELLO").c_bstr() );

这有点难看。实际上是否有这样的选项来创建 BSTR 文字?

动机:通过避免分配和释放,代码更易于阅读,运行时性能更快。

澄清:我只讨论调用者(即我们)拥有 BSTR 所有权的情况,例如:调用一个带有BSTR [in] 参数的函数。当然,将指向 BSTR 文字的指针提供给将继续尝试释放字符串的函数是愚蠢的。

【问题讨论】:

  • 不仅丑,还要等到有人打电话给SysFreeString() :)
  • BSTR 是按定义动态管理的。这个概念当然可以被扔进文字中,但它不会是 BSTR。如果在最终被释放的地方使用它,那将是灾难性的。 OLE 库有许多 位置(变体函数、编组器代码等),其中诸如 VARIANT 成员之类的东西在幕后进行管理。在这样的地方放置这样的东西将是灾难性的。您可以随时使用任何预制 BSTR 智能指针类,例如 bstr_tCComBSTR
  • @MattMcNabb 为什么要释放一个已经被释放的 BSTR?例如VariantChangeType,从加载的VARIANT 调用,其中“1000”的“文字”无效 BSTR 更改为VT_LONG 将是来自椽子的 UB。 BSTR [in,out] 按定义编组将释放输入 BSTR 并将其替换为输出-BSTR 多次。在字面 BSTR 中有 zero 意义。我刚刚重读了您的评论,我认为您同意。我同意,发送[in] BSTR 的东西不应该释放它(当然SysFreeString 除外)。
  • 回答我自己的问题...我猜一些内存检查工具可能会尝试检查提供给期望 BSTR 的函数的任何指针实际上是否与 OLE 分配表中存在的内容相对应
  • @WhozCraig 刚才试过了,here is the result ...

标签: c++ c++builder bstr


【解决方案1】:

为了跟进@MSalters 的回答,自定义的用户定义文字可能如下所示:

CComBSTR operator "" _bstr (const char* str, std::size_t len)
{
    return CComBSTR(len, str);
}

然后你可以这样做(因为CComBSTR 定义了BSTR 转换运算符):

iFoo->function( "HELLO"_bstr );

您甚至可以为多种输入字符串文字类型重载运算符:

CComBSTR operator "" _bstr (const wchar_t* str, std::size_t len)
{
    return CComBSTR(len, str);
}

CComBSTR operator "" _bstr (const char16_t* str, std::size_t len)
{
    return CComBSTR(len, (wchar_t*)str);
}

iFoo->function( L"HELLO"_bstr ); // calls wchar_t* version with UTF-16 encoded data

iFoo->function( u"HELLO"_bstr ); // calls char16_t* version with UTF-16 encoded data

iFoo->function( u8"HELLO"_bstr ); // calls char* version with UTF-8 encoded data...

注意最后一种情况。由于操作员不知道传递的是 ANSI 还是 UTF-8 数据,并且 CComBSTR 在传递 char* 数据时假定为 ANSI,因此您应该使用不同的文字后缀来区分,以便正确转换 UTF-8,例如:

CComBSTR operator "" _utf8bstr (const char* str, std::size_t len)
{
    std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>, wchar_t> conv;
    std::wstring wstr = conv.from_bytes(std::string(str, len));
    return CComBSTR(wstr.length(), wstr.c_str());
}

iFoo->function( u8"HELLO"_utf8bstr );

【讨论】:

  • 这实际上看起来像是用户定义文字的一个很好的例子。
  • 一定要注意不要写BSTR b = "hello"_bstr;
  • 是的,您必须改用CComBSTR b = "hello"_bstr; 或更好的auto b = "hello"_bstr;
【解决方案2】:

用户定义的文字将是要走的路:

"HELLO"_bstr 调用 template&lt;char...&gt; BSTR operator "" _bstr ( const char*, std::size_t) 然后可以调用 SysAllocString()

VS14 中的新功能。

[编辑]

根据 cmets,最好返回 _bstr_t 或其他拥有 SysAllocString() 结果所有权并隐式转换为 BSTR 的类。这个临时的将在完整表达式的末尾被销毁,因此 after iFoo-&gt;function( "HELLO"_bstr ); 返回。

【讨论】:

  • 这解决了“难看的语法”问题,尽管像iFoo-&gt;function( "hello"_bstr ); 这样使用会导致内存泄漏。
  • @MattMcNabb:iFoo-&gt;function 返回时不是调用了析构函数吗?
  • @MattMcNabb:我必须检查确切的规则。它可以通过返回一个隐式转换为 BSTR 但之后释放字符串的临时值来修复。但我认为传递 BSTR 意味着传递所有权。
  • @TonyK:BSTR 只是一个指针,如果操作符直接返回一个BSTR,则没有可调用的析构函数。您必须让运算符返回一个类的实例,而该类可以定义一个 BSTR 转换运算符。
  • @MSalters:标有[out] 的参数必须按地址传递,而不是按值传递。因此,您将无法将BSTR 传递给[out] 参数,因为它需要BSTR*。因此,返回 BSTR(直接或其他方式)的自定义 operator "" _bstr 无论如何只能与 [in] 参数一起使用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-01-10
  • 2021-11-07
  • 1970-01-01
  • 2020-12-17
  • 2020-05-10
  • 1970-01-01
相关资源
最近更新 更多