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

4

我有一个缓冲区(为简单起见,假设是一个固定大小的数组),我想从中构建一个std::string。该缓冲区可能以空字符结尾,也可能包含最后一个字符。如果缓冲区确实包含一个或多个空字符,则它们不应出现在结果string中。复制应在第一个空字符或缓冲区末尾停止,以先到者为准。

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

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

最佳和/或惯用的方法是什么?


通常的解决方案是让您的缓冲区以相同的方式填充。您可以将缓冲区增加1个元素,然后使最后一个元素成为空终止符,以便您始终具有空终止的缓冲区。 - NathanOliver
我并不是在创建缓冲区,而是由我无法控制的 API 提供给我的。(相关库直接从二进制文件格式中读取它,并且该格式还使用固定长度和可选的空终止符存储它。) - Parker Coates
2个回答

14

对于涉及C++标准库的许多问题,答案是要从迭代器的角度考虑问题。

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

std::string有一个构造函数,它接受两个迭代器firstlaststring将通过从first复制到但不包括last来创建。

因此,first显然应该是我们缓冲区的开头,而last应该是我们缓冲区中第一个空值或缓冲区末尾的下一个位置。方便的是,这正是调用std::find搜索缓冲区'\0'时返回的内容。


1
更简单的方法是跟踪缓冲区的末尾和大小。然后,您可以直接在字符串的构造中使用它。这还允许具有任意数据的std::string对象,包括嵌入在数据中间的空终止符。还要注意,如果buffer对象不支持它们(例如,如果您使用指针),则std::beginstd::end将无法工作。 - Some programmer dude
我知道缓冲区的大小。那不是问题所在。问题在于我不希望空值最终出现在我的 std::string 中。 - Parker Coates
你是否必须在这个阶段实际复制缓冲区中的 char,或者你是否可以像现在创建 std::string 一样创建一个 std::string_view - Ted Lyngmo
@ParkerCoates 使用迭代器很干净,但如果您想使用大小,则只需在buffer中搜索'\0',如果找到,则将其索引用作新字符串长度,否则使用buffer的完整大小:size_t str_size = ('\0'被发现) ? ( '\0'的索引) : (缓冲区大小); return std::string(&buffer[0], str_size); - Remy Lebeau

2
这里有一个针对已知大小的字符数组的简单方法。它类似于Parker的答案,但是只在构造函数参数中完成,并且特定于字符数组的问题。
#include <algorithm> // std::find
#include <iostream>
#include <string>

int main() {
  const char c[] = {'a', 'b', 'c', 'd', 'e'}; // prints abcde
  // const char c[] = { 'a','b','\0','d','\0' };    // test alternate: prints ab
  // const char c[] = { 'a','b','\0','d','e' };     // test alternate: prints ab
  std::string s{c, std::find(c, c + sizeof c, '\0')};
  std::cout << s << '\n';
  return 0;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接