使用C函数操作std :: string

时间:2019-01-09 08:57:25

标签: c++ c++17 stdstring

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

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

请注意我们首先需要填充本地缓冲区,然后将其复制到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);
   }

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

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

由于C ++ 17 std::string具有非常量data()方法,这意味着这是操作字符串的方法。所以这样做似乎很诱人:

std::string result;
result.resize(calculatedBufferSize);
snprint (result.data(), calculatedBufferSize, formatstring, value1, value2);
result.resize(strlen(result.c_str()));
return result;

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

请注意,我们的分配和复制工作量要少得多

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

说实话,尽管它似乎效率更高,但对我来说也看起来很“不合标准”。有人可以指出这是否是C ++ 17标准所允许的行为?还是有另一种方法可以更有效地进行这种操作?

请不要提及问题Manipulating std::string,因为该问题涉及更脏的逻辑(即使使用memset也是如此)。 同样不要回答我必须使用C ++流(std::string_stream,有效吗?说实话?)。有时,您只是在C语言中有想要重用的高效逻辑。

2 个答案:

答案 0 :(得分:7)

假设您没有将data()上的值设置为空字符以外的任何内容,那么修改data() + size()所指向的内容就可以了。来自[string.accessors]

  

charT* data() noexcept;

     

返回:指针p,使得p + i == addressof(operator[](i))中每个i的{​​{1}}。

     

复杂度:恒定时间。

     

备注:程序不得将存储在[0, size()]的值修改为p + size()以外的任何值;否则,行为是不确定的。


语句charT()看起来确实有些奇怪。 std::snprintf返回写入的字符数;使用该值来调整字符串的大小会更合适。此外,以正确的大小构造字符串看起来比构造立即调整大小的空字符串显得更加整洁:

result.resize(strlen(result.c_str()));

答案 1 :(得分:4)

一般方法对我来说不错。我会进行一些更改。

  1. 捕获snprinf的返回值。
  2. 使用它执行错误检查并避免调用strlen

std::string result;
result.resize(calculatedBufferSize);
int n = snprint (result.data(), calculatedBufferSize, formatstring, value1, value2);

if ( n < 0 )
{
   // Problem. Deal with the error.
}

result.resize(n);
return result;