簡體   English   中英

C ++使用std :: string,std :: wstring作為緩沖區

[英]C++ using std::string, std::wstring as a buffer

使用WinAPI,您經常會遇到一些將LPWSTR或LPSTR作為參數的方法。 有時這個指針實際上應該是指向緩沖區的指針,例如:

  int GetWindowTextW(HWND hWnd, LPWSTR lpString, int nMaxCount);

對這樣的緩沖區使用std::wstring是一個好主意,特別是我強烈需要生成std::wstring作為結果,並且不能用vector<wchar_t>替換它嗎?

std::wstring myWrapper(HWND hWnd){
    auto desiredBufferSize = GetWindowTextLengthW(hWnd);
    std::wstring resultWstr;
    resultWstr.resize(desiredBufferSize);
    auto ret = GetWindowText(hWnd,
                             const_cast<wchar_t*>(resultWstr.data()), // const_cast
                             resultWstr.size());
    // handle return code code
    return resultWstr;
}

data()c_str()字符串方法都返回const指針,因此我們必須使用const_cast來刪除const_cast ,這有時是一個不好的標志。 在這種情況下,這是一個好主意嗎? 我可以做得更好嗎?

使用String作為C-String

const char*std::string自動類型轉換,但不是其他方式。

字符'\\ 0'對於std :: string不是特殊的。

  • &s[0]用於寫訪問

確保字符串大小(不僅僅是容量)足夠大,以便進行C風格編寫。

  • s.c_str()用於只讀訪問

僅在下一次調用非常量方法之前有效。

代碼示例:

const int MAX_BUFFER_SIZE = 30;         // Including NULL terminator.         
string s(MAX_BUFFER_SIZE, '\0');      // Allocate enough space, NULL terminated
strcpy(&s[0], "This is source string.");    // Write, C++11 only (VS2010 OK)
printf("C str: '%s'\n", s.c_str());     // Read only: Use const whenever possible.

很有必要選擇標准的wstring。 然而,扔掉const ...永遠都不好

這里是一個臨時字符串包裝器 ,它自動創建一個緩沖區,將其指針傳遞給winapi函數,並將緩沖區的內容復制到您的字符串中並干凈地消失:

auto ret = GetWindowText(hWnd,
                         tmpstr (resultWstr, desiredBufferSize), 
                         resultWstr.size());

此解決方案適用於任何在返回之前寫入字符指針的Windows API函數(即沒有混合)。

它是如何工作的 ?

它基於C ++標准§12.2第3點:“ 臨時對象被破壞作為評估全表達式的最后一步(詞法上)包含它們被創建的點。(...)破壞的價值計算和副作用臨時對象僅與完整表達式相關聯,而不與任何特定子表達式相關聯。

這是它的實現:

typedef std::basic_string<TCHAR> tstring;  // based on microsoft's TCHAR

class tmpstr {
private:
    tstring &t;      // for later cpy of the result
    TCHAR *buff;     // temp buffer 
public:
    tmpstr(tstring& v, int ml) : t(v) {     // ctor 
          buff = new TCHAR[ml]{};           // you could also initialize it if needed
           std::cout << "tmp created\n";    // just for tracing, for proof of concept
        }
    tmpstr(tmpstr&c) = delete;              // No copy allowed
    tmpstr& operator= (tmpstr&c) = delete;  // No assignment allowed
    ~tmpstr() {                              
          t = tstring(buff);                // copy to string passed by ref at construction
          delete buff;                      // clean everyhing
          std::cout<< "tmp destroyed";      // just for proof of concept.  remove this line
        }
    operator LPTSTR () {return buff; }  // auto conversion to serve as windows function parameter without having to care
}; 

如您所見,第一行使用了typedef,以便與多個Windows編譯選項兼容(例如Unicode或不兼容)。 但是,當然,如果您願意,可以用wstringwchar_t替換tstringTCHAR

唯一的缺點是你必須重復緩沖區大小作為參數tmpstr構造函數和windows函數的參數。 但這就是你為這個功能寫一個wrepper的原因,不是嗎?

對於字符串緩沖區,為什么不使用char數組呢? :)

DWORD username_len = UNLEN + 1;
vector<TCHAR> username(username_len);
GetUserName(&username[0], &username_len);

公認的解決方案是過度思考的好例子。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM