使用C函数来操作std :: string

Pat*_*ick 4 c++ stdstring c++17

有时您需要填充std::string由C函数构造的字符.一个典型的例子是这样的:

constexpr static BUFFERSIZE{256};
char buffer[BUFFERSIZE];
snprint (buffer, BUFFERSIZE, formatstring, value1, value2);
return std::string(buffer);
Run Code Online (Sandbox Code Playgroud)

注意我们首先需要填充本地缓冲区,然后将其复制到std::string.

如果计算最大缓冲区大小并且不一定要存储在堆栈上,则示例会变得更复杂.例如:

constexpr static BUFFERSIZE{256};
if (calculatedBufferSize>BUFFERSIZE)
   {
   auto ptr = std::make_unique<char[]>(calculatedBufferSize);
   snprint (ptr.get(), calculatedBufferSize, formatstring, value1, value2);
   return std::string(ptr.get());
   }
else
   {
   char buffer[BUFFERSIZE];
   snprint (buffer, BUFFERSIZE, formatstring, value1, value2);
   return std::string(buffer);
   }
Run Code Online (Sandbox Code Playgroud)

这使代码更加复杂,如果calculatedBufferSize大于我们在堆栈上想要的,我们基本上执行以下操作:

  • 分配内存(make_unique)
  • 用想要的结果填充内存
  • 分配内存(std :: string)
  • 将内存复制到字符串
  • 释放记忆

由于C++ 17 std::string有一个非const data()方法,暗示这是操纵字符串的方法.所以这似乎很有诱惑力:

std::string result;
result.resize(calculatedBufferSize);
snprint (result.data(), calculatedBufferSize, formatstring, value1, value2);
result.resize(strlen(result.c_str()));
return result;
Run Code Online (Sandbox Code Playgroud)

我的实验表明,需要进行最后一次调整以确保正确报告字符串的长度. std::string::length()不搜索nul-terminator,它只返回大小(就像std::vector那样).

请注意,我们进行的分配和复制要少得多:

  • 分配内存(调整大小字符串)
  • 用想要的结果填充内存

说实话,虽然看起来效率更高,但对我来说它看起来也非常"不合标准".有人可以说明这是否是C++ 17标准允许的行为?或者是否有另一种方式以更有效的方式进行这种操作?

请不要参考问题操作std :: string,因为该问题涉及更多的脏逻辑(甚至使用memset).另外不要回答我必须使用C++流(std::string_stream,高效?,老实说?).有时您只需要在C中使用要重用的高效逻辑.

You*_*You 7

修改指向的内容data()很好,假设您没有将值设置为data() + size()除空字符以外的任何值.来自[string.accessors]:

charT* data() noexcept;

返回:一个指针p,p + i == addressof(operator[](i))用于每个iin [0, size()].

复杂性:恒定时间.

备注:程序不得将存储的值修改为p + size()除以外的任何值charT(); 否则,行为未定义.


不过,声明result.resize(strlen(result.c_str()));看起来确实有些奇怪.std::snprintf返回写入的字符数; 使用该值来调整字符串的大小会更合适.另外,构造具有正确大小的字符串看起来稍微整洁,而不是构造一个立即调整大小的空字符串:

std::string result(maxlen, '\0');
result.resize(std::max(0, std::snprintf(result.data(), maxlen, fmt, value1, value2)));
return result;
Run Code Online (Sandbox Code Playgroud)