我在Win32上的C++中有以下代码。它只是某个Win32 API上的C++扭曲,返回CHAR *
:
wstring expandEnvironmentVariables(const wstring & str)
{
DWORD neededSize = ExpandEnvironmentStrings(str.c_str(), nullptr, 0);
vector<WCHAR> expandedStr(neededSize);
if (0 == ExpandEnvironmentStrings(str.c_str(), expandedStr.data(), static_cast<DWORD>(expandedStr.size()))) {
return wstring(str);
}
return wstring(expandedStr.data());
}
这个代码让我困扰的是结果的双重副本。
- 通过API转换成CCD_ 2s的向量
- 从矢量转换为CCD_ 3
有没有一种方法可以在不对函数签名进行重大更改的情况下,仅使用一个副本来实现此代码。这是一个特定的示例,但我更感兴趣的是通用解决方案和使用std::wstring
/std::string
的正确方法,因为这种模式在代码中的许多地方都显示出来了。
关于C++端,您可以直接使用wstring
作为结果变量。
要获得指向非零大小的wstring
的缓冲区的指针,只需使用&s[0]
。
就像std::vector
一样,std::basic_string
有一个有保证的连续缓冲区。
对于退货,它可能会得到退货价值优化(RVO),如果没有,它将被移动。
免责声明:我没有检查API函数的文档。我不知道这个代码是否正确,甚至有意义。我只是假设。
wstring expandEnvironmentVariables(const wstring & str)
{
wstring expandedStr;
DWORD neededSize = ExpandEnvironmentStrings(str.c_str(),
nullptr, 0);
if (neededSize)
{
expandedStr.resize(neededSize);
if (0 == ExpandEnvironmentStrings(str.c_str(),
&expandedStr[0],
neededSize))
{
// pathological case requires a copy
expandedStr = str;
}
}
// RVO here
return expandedStr;
}
编辑:
仔细想想,既然我们使用的是c++,那就让我们全力以赴,通过一个信息丰富的嵌套异常链进行正确的错误检测和报告错误:
DWORD check_not_zero(DWORD retval, const char* context)
{
if(!retval)
throw std::system_error(GetLastError(),
std::system_category(),
context);
return retval;
}
std::wstring expandEnvironmentVariables(const std::wstring & str)
try
{
DWORD neededSize = check_not_zero(ExpandEnvironmentStrings(str.c_str(),
nullptr,
0),
"ExpandEnvironmentStrings1");
std::wstring expandedStr(neededSize, 0);
check_not_zero(ExpandEnvironmentStrings(str.c_str(),
&expandedStr[0],
neededSize),
"ExpandEnvironmentStrings2");
// RVO here
return expandedStr;
}
catch(...)
{
std::throw_with_nested(std::runtime_error("expandEnvironmentVariables() failed"));
}