如何从可能包含空值的缓冲区构造`std::string`?

huangapple go评论83阅读模式
英文:

How to construct a `std::string` from a buffer that may or may not contain a null?

问题

以下是翻译好的部分:

我有一个缓冲区(为简单起见,假设是一个固定大小的字符数组),我想要从中构造一个std::string。该缓冲区可能是以null结尾的,或者其内容可能延伸到并包括最后一个字符。如果缓冲区包含一个或多个null字符,它们不应该出现在生成的string中。复制应该在第一个null字符或缓冲区的末尾,以先到者为止。

这似乎是一个常见的需求,但在查看std::string API时,解决方案并不立即明显。

  • std::string有一个通过const char *和长度接受范围的构造函数,但愉快地继续复制null字符并将它们复制到字符串中。
  • 在构造string之前在缓冲区上调用std::strlen()不是一个选项,因为strlen首先要求字符串以null结尾。
  • 我们可以使用上述构造函数来创建一个包含null字符的string,然后将其调整大小为第一个null字符之前,但这会浪费内存,因为string将被过度分配。

什么是最佳和/或惯用的方法来做到这一点?

英文:

I have a buffer (for simplicity, let's say a fixed-sized array) of char that I would like to construct a std::string from. Said buffer may be null-terminated or its contents may run up to and include the very last character. If the buffer does contain one or more nulls, they should not end up in the resulting string. Copying should stop at the first null or the end of the buffer, whichever comes first.

This seems like a common enough thing to want to do, but the solution is not immediately obvious to me while looking at the std::string API.

  • std::string has a constructor taking a range via const char * and a length, but happily continues past nulls and copies them into the string.
  • Calling std::strlen() on the buffer before constructing the string isn't an option as strlen requires the string to be null terminated in the first place.
  • We could use the above constructor to make a string containing nulls and then resize it down to just before the first null, but that wastes memory as the string will be over-allocated.

What is the best and/or idiomatic way to do this?

答案1

得分: 14

The answer, as with so many questions regarding the C++ standard library, is to think about the problem in terms of iterators.

std::string stringFromBuffer(const auto & buffer)
{
    return std::string(std::begin(buffer),
                       std::find(std::begin(buffer), std::end(buffer), '
std::string stringFromBuffer(const auto & buffer)
{
    return std::string(std::begin(buffer),
                       std::find(std::begin(buffer), std::end(buffer), '\0'));
}
'
));
}

std::string has a constructor taking two iterators, first and last. The string will be created by copying from first up until but not including last.

So first should obviously be the beginning of our buffer, while last should either be the first null in our buffer or one past the end of the buffer. Conveniently, that is exactly what a call to std::find searching the buffer for '\0' will return.

英文:

The answer, as with so many questions regarding the C++ standard library, is to think about the problem in terms of iterators.

std::string stringFromBuffer(const auto & buffer)
{
    return std::string(std::begin(buffer),
                       std::find(std::begin(buffer), std::end(buffer), '
std::string stringFromBuffer(const auto & buffer)
{
return std::string(std::begin(buffer),
std::find(std::begin(buffer), std::end(buffer), '\0'));
}
')); }

std::string has a constructor taking two iterators, first and last. The string will be created by copying from first up until but not including last.

So first should obviously be the beginning of our buffer, while last should either be the first null in our buffer or one past the end of the buffer. Conveniently, that is exactly what a call to std::find searching the buffer for '\0' will return.

答案2

得分: 2

以下是您提供的代码的中文翻译:

这是一个针对已知大小的字符数组的简单方法。它类似于Parker的答案,但是在构造函数参数中完成,并且特定于一个由字符组成的数组的问题。

#include <algorithm> // std::find
#include <iostream>
#include <string>

int main() {
  const char c[] = {'a', 'b', 'c', 'd', 'e'}; // 输出abcde
  // const char c[] = { 'a','b','
#include <algorithm> // std::find
#include <iostream>
#include <string>

int main() {
  const char c[] = {'a', 'b', 'c', 'd', 'e'}; // 输出abcde
  // const char c[] = { 'a','b','\0','d','\0' };    // 测试替代方案:输出ab
  // const char c[] = { 'a','b','\0','d','e' };     // 测试替代方案:输出ab
  std::string s{c, std::find(c, c + sizeof c, '\0')};
  std::cout << s << '\n';
  return 0;
}
','d','
#include <algorithm> // std::find
#include <iostream>
#include <string>

int main() {
  const char c[] = {'a', 'b', 'c', 'd', 'e'}; // 输出abcde
  // const char c[] = { 'a','b','\0','d','\0' };    // 测试替代方案:输出ab
  // const char c[] = { 'a','b','\0','d','e' };     // 测试替代方案:输出ab
  std::string s{c, std::find(c, c + sizeof c, '\0')};
  std::cout << s << '\n';
  return 0;
}
' }; // 测试替代方案:输出ab
// const char c[] = { 'a','b','
#include <algorithm> // std::find
#include <iostream>
#include <string>

int main() {
  const char c[] = {'a', 'b', 'c', 'd', 'e'}; // 输出abcde
  // const char c[] = { 'a','b','\0','d','\0' };    // 测试替代方案:输出ab
  // const char c[] = { 'a','b','\0','d','e' };     // 测试替代方案:输出ab
  std::string s{c, std::find(c, c + sizeof c, '\0')};
  std::cout << s << '\n';
  return 0;
}
','d','e' }; // 测试替代方案:输出ab
std::string s{c, std::find(c, c + sizeof c, '
#include <algorithm> // std::find
#include <iostream>
#include <string>

int main() {
  const char c[] = {'a', 'b', 'c', 'd', 'e'}; // 输出abcde
  // const char c[] = { 'a','b','\0','d','\0' };    // 测试替代方案:输出ab
  // const char c[] = { 'a','b','\0','d','e' };     // 测试替代方案:输出ab
  std::string s{c, std::find(c, c + sizeof c, '\0')};
  std::cout << s << '\n';
  return 0;
}
'
)};
std::cout << s << '\n'; return 0; }

请注意,这段代码演示了如何从字符数组中创建一个字符串,以空字符('\0')作为终止符。

英文:

Here is a simple way for an array of chars of known size. It's similar to Parker's answer but is just done in the constructor argument and is specific to the question of an array of chars.

#include &lt;algorithm&gt; // std::find
#include &lt;iostream&gt;
#include &lt;string&gt;

int main() {
  const char c[] = {&#39;a&#39;, &#39;b&#39;, &#39;c&#39;, &#39;d&#39;, &#39;e&#39;}; // prints abcde
  // const char c[] = { &#39;a&#39;,&#39;b&#39;,&#39;
#include &lt;algorithm&gt; // std::find
#include &lt;iostream&gt;
#include &lt;string&gt;
int main() {
const char c[] = {&#39;a&#39;, &#39;b&#39;, &#39;c&#39;, &#39;d&#39;, &#39;e&#39;}; // prints abcde
// const char c[] = { &#39;a&#39;,&#39;b&#39;,&#39;\0&#39;,&#39;d&#39;,&#39;\0&#39; };    // test alternate: prints ab
// const char c[] = { &#39;a&#39;,&#39;b&#39;,&#39;\0&#39;,&#39;d&#39;,&#39;e&#39; };     // test alternate: prints ab
std::string s{c, std::find(c, c + sizeof c, &#39;\0&#39;)};
std::cout &lt;&lt; s &lt;&lt; &#39;\n&#39;;
return 0;
}
&#39;,&#39;d&#39;,&#39;
#include &lt;algorithm&gt; // std::find
#include &lt;iostream&gt;
#include &lt;string&gt;
int main() {
const char c[] = {&#39;a&#39;, &#39;b&#39;, &#39;c&#39;, &#39;d&#39;, &#39;e&#39;}; // prints abcde
// const char c[] = { &#39;a&#39;,&#39;b&#39;,&#39;\0&#39;,&#39;d&#39;,&#39;\0&#39; };    // test alternate: prints ab
// const char c[] = { &#39;a&#39;,&#39;b&#39;,&#39;\0&#39;,&#39;d&#39;,&#39;e&#39; };     // test alternate: prints ab
std::string s{c, std::find(c, c + sizeof c, &#39;\0&#39;)};
std::cout &lt;&lt; s &lt;&lt; &#39;\n&#39;;
return 0;
}
&#39; }; // test alternate: prints ab // const char c[] = { &#39;a&#39;,&#39;b&#39;,&#39;
#include &lt;algorithm&gt; // std::find
#include &lt;iostream&gt;
#include &lt;string&gt;
int main() {
const char c[] = {&#39;a&#39;, &#39;b&#39;, &#39;c&#39;, &#39;d&#39;, &#39;e&#39;}; // prints abcde
// const char c[] = { &#39;a&#39;,&#39;b&#39;,&#39;\0&#39;,&#39;d&#39;,&#39;\0&#39; };    // test alternate: prints ab
// const char c[] = { &#39;a&#39;,&#39;b&#39;,&#39;\0&#39;,&#39;d&#39;,&#39;e&#39; };     // test alternate: prints ab
std::string s{c, std::find(c, c + sizeof c, &#39;\0&#39;)};
std::cout &lt;&lt; s &lt;&lt; &#39;\n&#39;;
return 0;
}
&#39;,&#39;d&#39;,&#39;e&#39; }; // test alternate: prints ab std::string s{c, std::find(c, c + sizeof c, &#39;
#include &lt;algorithm&gt; // std::find
#include &lt;iostream&gt;
#include &lt;string&gt;
int main() {
const char c[] = {&#39;a&#39;, &#39;b&#39;, &#39;c&#39;, &#39;d&#39;, &#39;e&#39;}; // prints abcde
// const char c[] = { &#39;a&#39;,&#39;b&#39;,&#39;\0&#39;,&#39;d&#39;,&#39;\0&#39; };    // test alternate: prints ab
// const char c[] = { &#39;a&#39;,&#39;b&#39;,&#39;\0&#39;,&#39;d&#39;,&#39;e&#39; };     // test alternate: prints ab
std::string s{c, std::find(c, c + sizeof c, &#39;\0&#39;)};
std::cout &lt;&lt; s &lt;&lt; &#39;\n&#39;;
return 0;
}
&#39;)}; std::cout &lt;&lt; s &lt;&lt; &#39;\n&#39;; return 0; }

huangapple
  • 本文由 发表于 2023年4月20日 00:58:37
  • 转载请务必保留本文链接:https://go.coder-hub.com/76057077.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定