2009-11-30 60 views
3

當通過SysAllocString(L"")SysAllocStringLen(str, 0)分配一個空的BSTR時,您總是會得到一個新的BSTR(至少通過我所做的測試)。 BSTR通常不會共享(如Java/.NET插件),因爲它們是可變的,但空字符串對於所有意圖和目的都是不可變的。爲什麼COM不使用靜態空的BSTR?

我的問題(終於)是爲什麼不利用COM創建一個空BSTR時總是返回相同的字符串(在SysFreeString忽略它)瑣碎優化?是否有一個令人信服的理由不這樣做(因爲我的推理是有缺陷的)還是隻是認爲它不夠重要?

回答

2

我猜(這是隻是一個猜測),這種優化不被視爲重要的足以執行。

雖然從Windows過去的內存消耗很多事情是在API設計(參見Raymond Chen的文章)的主要因素,不像Java的或.NET的字符串實習的好處是相當小的,因爲它們只適用於一個單一的字符串,只有六個字節長。一個程序在任何時間點必須保存多少空串?這個數字是否足以保證優化或實際上可以忽略不計?

4

我不會談論COM中的習慣用法,但在C++,Java等中,有一個期望,如果你使用一個對象,它不會比較相等(就地址/對象身份而言)到任何其他物體。當您使用基於身份的映射時,此屬性非常有用,例如,作爲Java中的IdentityHashMap中的鍵。出於這個原因,我不認爲空的字符串/對象應該是這個規則的例外。

編寫良好的COM對象將允許您將NULL傳遞給BSTR參數,並將其視爲等同於空字符串。 (雖然這不適用於MSXML,但我已經學會了很難的方法。:-P)

+0

字符串實習適用於:1.字符串常量,和2串在那裏實習()被調用。但是,在使用'new'的地方,對象不等式仍然適用:'String a = new String(「foo」),b = new String(「foo」);聲明一個!= b; assert a.equals(b);' – 2009-11-30 19:47:09

+0

另外:'assert a.intern()==「foo」; assert b.intern()==「foo」;' – 2009-11-30 19:48:22

+0

啊,好的。學到了新東西。對不起,然後:-) – Joey 2009-11-30 20:36:51

2

它不是COM分配BSTR,因爲它是提供它的Windows子系統。

空的BSTR不能共享一個靜態實例,因爲有些功能可以重新分配/調整BSTR的大小。請參閱SysReAllocString。雖然沒有提到樂觀的分配行爲,但不能認爲調用者在調用後永遠不會收到原始的BSTR。

SysReAllocString @ MSDN

編輯:

在一些反思,我認識到,即使在佔SysReAllocString,人們可以與共享一個空的BSTR啓動,調用SysReAllocString,並獲得一個新的BSTR無任何破壞行爲。所以可以爲了爭論而打折扣。我的錯。

然而,我認爲一個空的BSTR的想法帶來了比人們想象的更多的包袱。我寫了一些測試程序,看看能否得到一些有衝突或有趣的結果。在運行我的測試並計算結果之後,我認爲對於您的問題的最佳答案是,如果所有請求都獲得了自己的BSTR,那麼對每個參與者來說都是最安全的。有許多時髦的方法可以讓BSTRs報告不同長度的零長度字符串和字節。即使在某些地方有一些返回共享實例的優化,當口頭描述空的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 
+0

但是'SysReAllocString'創建一個新的指針,所以空字符串仍然是不可變的,你只需分配一個足夠大的新字符串。 – Motti 2009-11-30 20:08:02

+0

它可以創建一個新的指針,但它也可以爲原始的BSTR提供一個新的分配長度。最近版本的Windows中的當前實現可能默認爲新的BSTR,但較早的實現可能會有不同的操作,可能是32位Windows/COM版本的Windows。 – meklarian 2009-11-30 20:20:12

+0

從頭開始評論。看到更新的答案。 – meklarian 2009-11-30 21:42:23

相關問題