带有单个副本的初始化std::字符串

Init std::string with single copy

本文关键字:std 字符串 初始化 单个 副本      更新时间:2023-10-16

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

这个代码让我困扰的是结果的双重副本。

  1. 通过API转换成CCD_ 2s的向量
  2. 从矢量转换为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"));
}