使用单个副本的init std :: string

时间:2015-10-29 07:45:30

标签: c++ c++11 stdstring

我在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());
}

令我困扰的是这段代码,是结果的双重副本。

    通过API将
  1. 转换为WCHAR s。
  2. 的向量
  3. 从矢量到std::wstring
  4. 有没有办法只使用一个副本来实现此代码,并且不会对函数的签名进行重大更改。 这是一个具体示例,但我对使用std::wstring / std::string的一般解决方案和正确方法更感兴趣,因为此模式在代码中的许多位置显示。< / p>

2 个答案:

答案 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"));
}