[英]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
,這有時是一個不好的標志。 在這種情況下,這是一個好主意嗎? 我可以做得更好嗎?
從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或不兼容)。 但是,當然,如果您願意,可以用wstring
和wchar_t
替換tstring
和TCHAR
。
唯一的缺點是你必須重復緩沖區大小作為參數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.