我在Win32上的C ++中有以下代码。它只是一些返回CHAR *
的Win32 API上的C ++ warp:
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());
}
令我困扰的是这段代码,是结果的双重副本。
WCHAR
s。std::wstring
。有没有办法只使用一个副本来实现此代码,并且不会对函数的签名进行重大更改。
这是一个具体示例,但我对使用std::wstring
/ std::string
的一般解决方案和正确方法更感兴趣,因为此模式在代码中的许多位置显示。< / p>
答案 0 :(得分:3)
关于C ++方面,您可以直接使用wstring
作为结果变量。
要获得指向非{0} wstring
的缓冲区的指针,只需使用&s[0]
。
就像std::vector
一样,std::basic_string
有一个保证连续的缓冲区。
对于返回,它可能会获得返回值优化(RVO),如果没有,那么它将被移动。
免责声明:我还没有查看API函数的文档。我不知道这段代码是否正确甚至有意义。我只是假设那样。
答案 1 :(得分:3)
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"));
}