在BSTR
或SysAllocString(L"")
分配空SysAllocStringLen(str, 0)
时,您总会得到一个新BSTR
(至少通过我做的测试)。 BSTR
通常不共享(如Java / .NET interment),因为它们是可变的,但是对于所有意图和目的,空字符串是不可变的。
我的问题(最后)是为什么COM在创建空BSTR
时(并在SysFreeString
忽略它时)不会使用总是返回相同字符串的简单优化?有没有令人信服的理由不这样做(因为我的推理存在缺陷),还是只是认为它不够重要?
答案 0 :(得分:4)
我不能谈论COM中的惯用语,但在C ++,Java等中,有一种期望,如果你new
一个对象,它将不会相等(就地址/对象的身份而言)关注任何其他对象。当您使用基于身份的映射(例如,作为Java中IdentityHashMap
中的键)时,此属性非常有用。因此,我不认为空字符串/对象应该是此规则的例外。
编写良好的COM对象允许您将NULL
传递给BSTR
参数,并将其视为等效于空字符串。 (但这对MSXML不起作用,因为我学到了很难的方法。:-P)
答案 1 :(得分:2)
我猜(并且是的,这只是猜测)这种优化被认为不够重要。
虽然很多东西来自Windows过去的内存消耗是API设计中的一个主要因素(参见Raymond Chen的文章),但与Java或.NET的字符串实习不同,它的好处相当小,因为它们只适用于单个字符串。只有六个字节长。一个程序在任何一个时间点都要在内存中保留多少个空字符串?这个数字是否足以保证优化还是实际上可以忽略不计?
答案 2 :(得分:2)
不是COM分配BSTR就像提供它的Windows子系统一样。
空BSTR不能共享静态实例,因为有些函数可以重新分配/调整BSTR的大小。请参阅SysReAllocString。虽然没有提到乐观的分配行为,但不能假设呼叫者在呼叫后永远不会收到原始的BSTR。
修改强>
经过反思后,我意识到即使在计算SysReAllocString时,也可以从共享的空BSTR开始,调用SysReAllocString,并接收新的BSTR而不会出现任何中断行为。因此,为了论证,这可以打折扣。我的错。
然而,我认为空BSTR的想法比人们想象的要多得多。我写了一些测试程序,看看我是否能得到一些冲突或有趣的结果。在运行我的测试并计算结果之后,我认为对您的问题的最佳答案是,如果所有请求都获得了自己的BSTR,那么对所有参与者来说这是最安全的。有许多时髦的方法可以让BSTR报告不同类型的零长度,包括字符串和字节。即使在某些地方存在一些返回共享实例的优化,但在口头描述空BSTR与具有空字符串长度和实际分配长度的实际BSTR时存在大量混淆的空间。例如,诸如“没有字符串分配长度的BSTR可能会被遗忘”之类的语句可能会导致一些加重的内存泄漏(请参阅下面关于字节分配的BSTR的测试)。
此外,尽管有些COM组件允许使用NULL指针(0值)BSTR作为参数,但假设所有COM组件都支持它是不安全的。只有当主叫方和被叫方同意允许这样做时,这才是安全的。每个人最安全的行为是假设如果BSTR被移交,它可能具有零定义长度,需要处理零定义长度的情况,并且需要一些不是NULL指针的值。至少,这使得编写代理/存根代码和其他棘手的任务变得更加容易。
我的第一个测试程序尝试了一些不常见的分配方法。请注意,您可以获得报告的SysStringLen长度为0的BSTR,但具有实际字节分配。另外,我正式承认bstr5和bstr6不是干净的分配方法。
这是来源:
int _tmain(int argc, _TCHAR* argv[])
{
BSTR bstr1 = SysAllocString(L"");
BSTR bstr2 = SysAllocStringLen(NULL, 0);
BSTR bstr3 = SysAllocStringLen(NULL, 1);
*bstr3 = '\0';
BSTR bstr4 = SysAllocStringLen(L"some string", 0);
BSTR bstr5 = SysAllocStringByteLen((LPCSTR)L"", 1);
BSTR bstr6 = SysAllocStringByteLen((LPCSTR)L"", 2);
BSTR bstr7 = SysAllocStringByteLen("", 1);
BSTR bstr8 = SysAllocStringByteLen("\0\0", 2);
BSTR bstr9 = SysAllocStringByteLen(NULL, 0);
BSTR bstr10 = SysAllocStringByteLen(NULL, 1);
_tprintf(_T("L\"\"-sourced BSTR\r\n")
_T("\tBSTR=0x%8.8x, length %d, %d bytes\r\n"),
bstr1, SysStringLen(bstr1), SysStringByteLen(bstr1));
_tprintf(_T("NULL BSTR with no alloc length\r\n")
_T("\tBSTR=0x%8.8x, length %d, %d bytes\r\n"),
bstr2, SysStringLen(bstr2), SysStringByteLen(bstr2));
_tprintf(_T("NULL BSTR with 1 OLECHAR alloc length\r\n")
_T("\tBSTR=0x%8.8x, length %d, %d bytes\r\n"),
bstr3, SysStringLen(bstr3), SysStringByteLen(bstr3));
_tprintf(_T("L\"some string\"-sourced BSTR with no alloc length\r\n")
_T("\tBSTR=0x%8.8x, length %d, %d bytes\r\n"),
bstr4, SysStringLen(bstr4), SysStringByteLen(bstr4));
_tprintf(_T("L\"\"-sourced BSTR with 1 byte alloc length\r\n")
_T("\tBSTR=0x%8.8x, length %d, %d bytes\r\n"),
bstr5, SysStringLen(bstr5), SysStringByteLen(bstr5));
_tprintf(_T("L\"\"-sourced BSTR with 2 byte alloc length\r\n")
_T("\tBSTR=0x%8.8x, length %d, %d bytes\r\n"),
bstr6, SysStringLen(bstr6), SysStringByteLen(bstr6));
_tprintf(_T("\"\"-sourced BSTR with 1 byte alloc length\r\n")
_T("\tBSTR=0x%8.8x, length %d, %d bytes\r\n"),
bstr7, SysStringLen(bstr7), SysStringByteLen(bstr7));
_tprintf(_T("\"\\0\\0\"-sourced BSTR with 2 byte alloc length\r\n")
_T("\tBSTR=0x%8.8x, length %d, %d bytes\r\n"),
bstr8, SysStringLen(bstr8), SysStringByteLen(bstr8));
_tprintf(_T("NULL-sourced BSTR with 0 byte alloc length\r\n")
_T("\tBSTR=0x%8.8x, length %d, %d bytes\r\n"),
bstr9, SysStringLen(bstr9), SysStringByteLen(bstr9));
_tprintf(_T("NULL-sourced BSTR with 1 byte alloc length\r\n")
_T("\tBSTR=0x%8.8x, length %d, %d bytes\r\n"),
bstr10, SysStringLen(bstr10), SysStringByteLen(bstr10));
SysFreeString(bstr1);
SysFreeString(bstr2);
SysFreeString(bstr3);
SysFreeString(bstr4);
SysFreeString(bstr5);
SysFreeString(bstr6);
SysFreeString(bstr7);
SysFreeString(bstr8);
SysFreeString(bstr9);
SysFreeString(bstr10);
return 0;
}
以下是我收到的结果。
L""-sourced BSTR
BSTR=0x00175bdc, length 0, 0 bytes
NULL BSTR with no alloc length
BSTR=0x00175c04, length 0, 0 bytes
NULL BSTR with 1 OLECHAR alloc length
BSTR=0x00175c2c, length 1, 2 bytes
L"some string"-sourced BSTR with no alloc length
BSTR=0x00175c54, length 0, 0 bytes
L""-sourced BSTR with 1 byte alloc length
BSTR=0x00175c7c, length 0, 1 bytes
L""-sourced BSTR with 2 byte alloc length
BSTR=0x00175ca4, length 1, 2 bytes
""-sourced BSTR with 1 byte alloc length
BSTR=0x00175ccc, length 0, 1 bytes
"\0\0"-sourced BSTR with 2 byte alloc length
BSTR=0x00175cf4, length 1, 2 bytes
NULL-sourced BSTR with 0 byte alloc length
BSTR=0x00175d1c, length 0, 0 bytes
NULL-sourced BSTR with 1 byte alloc length
BSTR=0x00175d44, length 0, 1 bytes
我的下一个测试程序显示,尺寸向下的改变可能会返回相同的BSTR。这是一个简短的片段,可以为您演示这一点,以及我收到的输出。我也将它增加到原来的长度以上,并且仍然收到相同的BSTR。这至少表明,人们不能假设没有长度的BSTR不能增加。
int _tmain(int argc, _TCHAR* argv[])
{
BSTR bstr1 = SysAllocString(L"hello world!");
_tprintf(_T("L\"hello world!\"-sourced BSTR\r\n")
_T("\tBSTR=0x%8.8x, length %d, %d bytes\r\n"),
bstr1, SysStringLen(bstr1), SysStringByteLen(bstr1));
_tprintf(_T("resizing bstr1 to source L\"\"\r\n"));
SysReAllocString(&bstr1, L"");
_tprintf(_T("L\"\"-sourced reallocated BSTR\r\n")
_T("\tBSTR=0x%8.8x, length %d, %d bytes\r\n"),
bstr1, SysStringLen(bstr1), SysStringByteLen(bstr1));
_tprintf(_T("resizing bstr1 to source L\"hello!\"\r\n"));
SysReAllocString(&bstr1, L"hello!");
_tprintf(_T("L\"\"-sourced reallocated BSTR\r\n")
_T("\tBSTR=0x%8.8x, length %d, %d bytes\r\n"),
bstr1, SysStringLen(bstr1), SysStringByteLen(bstr1));
_tprintf(_T("resizing bstr1 to source L\"hello world!+\"\r\n"));
SysReAllocString(&bstr1, L"hello world!+");
_tprintf(_T("L\"\"-sourced reallocated BSTR\r\n")
_T("\tBSTR=0x%8.8x, length %d, %d bytes\r\n"),
bstr1, SysStringLen(bstr1), SysStringByteLen(bstr1));
SysFreeString(bstr1);
return 0;
}
在我的工作站(Windows XP)上运行此程序,返回以下结果。我有兴趣知道是否还有其他人在路上的任何地方获得新的BSTR。
L"hello world!"-sourced BSTR
BSTR=0x00175bdc, length 12, 24 bytes
resizing bstr1 to source L""
L""-sourced reallocated BSTR
BSTR=0x00175bdc, length 0, 0 bytes
resizing bstr1 to source L"hello!"
L"hello!"-sourced reallocated BSTR
BSTR=0x00175bdc, length 6, 12 bytes
resizing bstr1 to source L"hello world!+"
L"hello world!+"-sourced reallocated BSTR
BSTR=0x00175bdc, length 13, 26 bytes
我再次尝试了这个程序,但这次是从一个空的widechar字符串(L“”)开始。这应该涵盖从没有定义字符串长度的BSTR开始,并查看它是否实际具有隐式大小的情况。当我运行它时,我发现我仍然收到了相同的BSTR。不过,我希望结果可能会有所不同。
这是来源:
int _tmain(int argc, _TCHAR* argv[])
{
BSTR bstr1 = SysAllocString(L"");
_tprintf(_T("L\"\"-sourced BSTR\r\n")
_T("\tBSTR=0x%8.8x, length %d, %d bytes\r\n"),
bstr1, SysStringLen(bstr1), SysStringByteLen(bstr1));
_tprintf(_T("resizing bstr1 to source L\"hello world!\"\r\n"));
SysReAllocString(&bstr1, L"hello world!");
_tprintf(_T("L\"hello world!\"-sourced reallocated BSTR\r\n")
_T("\tBSTR=0x%8.8x, length %d, %d bytes\r\n"),
bstr1, SysStringLen(bstr1), SysStringByteLen(bstr1));
_tprintf(_T("resizing bstr1 to source L\"hello!\"\r\n"));
SysReAllocString(&bstr1, L"hello!");
_tprintf(_T("L\"hello!\"-sourced reallocated BSTR\r\n")
_T("\tBSTR=0x%8.8x, length %d, %d bytes\r\n"),
bstr1, SysStringLen(bstr1), SysStringByteLen(bstr1));
_tprintf(_T("resizing bstr1 to source L\"hello world!+\"\r\n"));
SysReAllocString(&bstr1, L"hello world!+");
_tprintf(_T("L\"hello world!+\"-sourced reallocated BSTR\r\n")
_T("\tBSTR=0x%8.8x, length %d, %d bytes\r\n"),
bstr1, SysStringLen(bstr1), SysStringByteLen(bstr1));
SysFreeString(bstr1);
return 0;
}
结果:
L""-sourced BSTR
BSTR=0x00175bdc, length 0, 0 bytes
resizing bstr1 to source L"hello world!"
L"hello world!"-sourced reallocated BSTR
BSTR=0x00175bdc, length 12, 24 bytes
resizing bstr1 to source L"hello!"
L"hello!"-sourced reallocated BSTR
BSTR=0x00175bdc, length 6, 12 bytes
resizing bstr1 to source L"hello world!+"
L"hello world!+"-sourced reallocated BSTR
BSTR=0x00175bdc, length 13, 26 bytes