使用std::string存储二进制数据是否不合适?

3

我在这个问题中看到有人修改了一个有效的代码片段,原因是第二个答案的作者说:

我认为使用std::string对象存储二进制数据不太合适。

那么,我为什么不能这样做呢?


1
你有什么理由会这样做,而不是使用 std::vector<char> - juanchopanza
1
因为在C++03中,std::string允许进行写时复制,并在数据块末尾添加\0吗?它并不是设计用于存储任意二进制数据块。它的设计目的是实现字符字符串的概念。 - juanchopanza
@juanchopanza COW(被证明在这里大多数情况下都不好)在C++11中已经不再允许,那么添加的零终止符如何妨碍我?唯一的好处是在没有真正文本时不使用字符串。 - Deduplicator
@juanchopanza:你完全掌控。所以在你的数据后面存储了一个0(不包括在计数中),这会如何阻碍你?它也可能是垃圾,谁在乎呢? - Deduplicator
例如,在某些情况下,使用&s[0]访问底层数据块可能不安全,而在使用std::vector时则可以。 - juanchopanza
显示剩余4条评论
1个回答

7
在处理二进制数据时,我认为最好的选择是使用std::vector<unsigned char>
虽然使用std::string在技术上可以工作,但会给用户传递错误的信息,让他们误以为正在处理的是文本数据。
另一方面,能够接受字符串中的任何字节非常重要,因为有时您知道内容是文本,但编码方式未知。强制std::string仅包含有效和解码文本将成为现实世界应用的重大限制。
这种限制是我不喜欢QString的少数几件事之一:这种限制使得例如使用文件选择对话框打开文件变得不可能,如果文件名具有“错误”的(意外的)编码或编码实际上无效(其中包含错误) 。

也许可以补充说明,由于他们不支持UTF-8,因此只能接受特定的正确文本超集。 - Deduplicator
@Deduplicator:QString不是由字节构成的,而是由Unicode字符构成的。问题在于,有时候从字节转换为Unicode字符是不可能的,因为你不知道编码方式。Linux文件系统是编码无关的,所以你可以在同一个目录中拥有既使用iso-8859编码又使用utf-8编码的文件名。这当然并不完美(无论你尝试什么,屏幕上都会看到奇怪的字符),但是因为无法将文件名存储在字符串中而无法打开文件要更糟糕得多。 - 6502
1
使用Unicode时,我认为你指的是UTF-16。而UTF-8允许您通过假装输入是有效的来忽略该情况。嗯,这只是一个示例中的次要问题,所以并不重要。 - Deduplicator
@Deduplicator:我的意思是Unicode,因为QString的限制在于它只接受解码后的文本作为内容。无论它是16位还是32位都没关系。问题在于有时候你会得到代表文本的字节,但你无法解码它们(例如因为你不知道所使用的编码方式,或者因为存在编码错误)。对于许多操作来说,这完全不相关(例如将这些字节作为文件名传递给fopen),而仅要求解码后的文本会创建一个可用性问题。例如,使用qt编写grep将会很困难,因为正则表达式只能与qstring一起使用。 - 6502

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