2010-03-13 71 views
3

許多windows APIs都會獲取指向緩​​衝區和大小元素的指針,但結果需要放入C++字符串中。 (我在這裏使用的是Windows的Unicode所以他們wstrings)混合C++標準字符串和窗口API

下面是一個例子: -

#include <iostream> 
#include <string> 
#include <vector> 
#include <windows.h> 

using namespace std; 

// This is the method I'm interested in improving ... 
wstring getComputerName() 
{ 
    vector<wchar_t> buffer; 
    buffer.resize(MAX_COMPUTERNAME_LENGTH+1); 
    DWORD size = MAX_COMPUTERNAME_LENGTH; 

    GetComputerNameW(&buffer[0], &size); 

    return wstring(&buffer[0], size); 
} 

int main() 
{ 
    wcout << getComputerName() << "\n"; 
} 

我真正的問題是,這是寫getComputerName功能,使得它適合的最佳方式C++更好,還是有更好的方法?我沒有看到任何方式直接使用字符串,沒有通過矢量直接使用,除非我錯過了什麼?它工作正常,但不知何故似乎有點難看。問題不在於特定的API,而僅僅是一個簡單的例子。

回答

7

在這種情況下,我看不到什麼std :: vector帶給聚會。 MAX_COMPUTERNAME_LENGTH不可能非常大,所以我只是簡單地使用一個C風格的數組作爲臨時緩衝區。

+0

好吧,我的例子是一個糟糕的,我用了一個載體,因爲我可能直到運行時才知道我想要緩衝區有多大。我完全同意這個例子沒有必要 – jcoder 2010-03-13 10:16:16

+0

@JB嗯,我不認爲有任何一般規則 - 你必須以你自己的方式處理你使用的每個API。這部分是因爲整個API背後並沒有一個完整的設計理念。 – 2010-03-13 10:23:45

+0

好的,謝謝,真的,我只是想檢查我不會錯過任何明顯的更好的方法來實現這個 – jcoder 2010-03-13 10:25:39

2

我會說,既然你已經在抽象的Windows API更通用的C++接口後面的任務,破除矢量乾脆,不要理會wstring的構造函數:

wstring getComputerName() 
{ 
    wchar_t name[MAX_COMPUTERNAME_LENGTH + 1]; 
    DWORD size = MAX_COMPUTERNAME_LENGTH; 

    GetComputerNameW(name, &size); 

    return name; 
} 

此功能將返回一個有效的wstring對象。

+0

getComputerName()應該返回一個LPCWSTR(const wchar_t *)並讓調用者根據需要構造一個wstring,可以是靜態的。 – 2010-03-13 12:43:27

+0

我以爲OP想要抽象Windows API,而是使用一致的C++接口,在這種情況下,我相信返回一個C++字符串(可能是const)是要走的路,而不是更多的「const wchar_t *」。還是你完全提到了其他的東西? – amn 2010-03-13 12:50:02

+0

我認爲Alain的觀點是,在返回時自動轉換沒有太大好處 - 調用者可以編寫'wstring n = getComputerName();'或'wstring n; n = getComputerName();'不管返回類型是'wstring'還是'wchar_t *'。所以他說的是做最大的靈活性的事情。在這種情況下,我不太喜歡他的「靜態」緩衝區,但我不認爲這種改變是值得使該函數非線程安全的,因爲YAGN wchar_t *返回。所以在這種情況下,我認爲這是值得轉換的功能。 – 2010-03-13 12:56:21

3

請參閱this answer另一個問題。它提供了一個StringBuffer類來處理這種情況非常乾淨。

1

我會使用該向量。爲了迴應你說你選擇了一個不好的例子,假裝我們沒有合理的字符串長度上限。然後它不是那麼容易:

#include <string> 
#include <vector> 
#include <windows.h> 

using std::wstring; 
using std::vector; 

wstring getComputerName() 
{ 
    DWORD size = 1; // or a bigger number if you like 
    vector<wchar_t> buffer(size); 
    while ((GetComputerNameW(&buffer[0], &size) == 0)) 
    { 
     if (GetLastError() != ERROR_BUFFER_OVERFLOW) aargh(); // handle error 
     buffer.resize(++size); 
    }; 
    return wstring(&buffer[0], size); 
} 

在實踐中,你可能會寫入字符串,但我不完全確定。除了標準中的內容之外,您當然需要通過實施std::wstring所做的額外保證,但我希望MSVC的字符串可能是正確的。

我認爲,如果wstring::referencewchar_t&那麼你是排序。 21.3.4定義非const operator[]返回reference,並返回data()[pos]。因此,如果reference只是一個普通的wchar_t&,那麼通過該引用沒有激發寫時複製行爲的範圍,並且該字符串實際上可以通過指針&buffer[0]修改。我認爲。這裏的基本問題是標準允許實現更多的靈活性而不是需要的。

儘管爲了避免複製一個字符串而做了大量的工作和評論,所以我從來沒有覺得需要避免中間數組/矢量。

+0

嗯,是的,我想這不假設有關wstring的假設,但由於這段代碼本質上依賴於平臺,無論如何,這不是一個問題, – jcoder 2010-03-13 14:03:17

+0

嗯,GetComputerNameW只要求你在Windows上,而'wstring'的必要條件可以想像由一些Windows編譯器/庫實現滿足,但不是其他。所以做出假設確實會使代碼更「依賴」平臺。就是說,它適用於使用向量處理的實現的子集,子集可能是嚴格的,即使它不嚴格,每個實現需要額外的工作才能證明它不是。爲了說明這一點,我的計算機名稱全部爲5個字符;-) – 2010-03-13 14:32:17