C ++使用std :: string,std :: wstring作为缓冲区

时间:2014-09-07 21:55:23

标签: c++ string winapi

使用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来删除constness,这有时是一个坏符号。在这种情况下,这是一个好主意吗?我能做得更好吗?

3 个答案:

答案 0 :(得分:2)

使用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.

答案 1 :(得分:2)

很有必要选择标准的wstring。然而,扔掉const ......永远不会好。

这里有一个临时字符串包装器,它自动创建一个缓冲区,将其指针传递给winapi函数,并将缓冲区的内容复制到你的字符串中并干净利落地消失:

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

此解决方案适用于任何Windows API 函数,该函数在返回之前写入字符指针(即没有同步)。

它是如何运作的?

它基于C ++标准§12.2第3点:“临时对象被破坏作为评估全表达式的最后一步(词法上)包含创建它们的点。(...)值销毁临时对象的计算和副作用只与full-expression有关,而与任何特定的子表达无关。“。

这是实施:

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 or not)。但是,当然,如果您愿意,可以将tstringTCHAR替换为wstringwchar_t

唯一的缺点是你必须重复缓冲区大小作为参数tmpstr构造函数和windows函数的参数。但这就是你为这个功能写一个wrepper的原因,不是吗?

答案 2 :(得分:0)

对于字符串缓冲区,为什么不只使用char数组? :)

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

公认的解决方案是一个很好的例子。