std::string 或 std::vector<char> 来保存原始数据



我希望这个问题适合stackoverflow。。。在std::string中存储原始数据字节(8位)与在std::vector<char>中存储它们之间的区别是什么。我正在从文件中读取二进制数据,并将这些原始字节存储在std::string中。这样做效果很好,没有任何问题。我的程序按预期运行。然而,其他程序员更喜欢std::vector<char>方法,并建议我停止使用std::string,因为它对原始字节不安全。所以我想知道为什么使用std::string来保存原始数据字节是不安全的?我知道std::string最常用于存储ASCII文本,但字节就是字节,所以我不理解std::vector<char>的偏好。

谢谢你的建议!

问题不在于它是否有效。问题是,对于下一个阅读你代码的人来说,这是完全令人困惑的。std::string用于显示文本。任何阅读你的代码的人都会预料到这一点。使用std::vector<char>,您可以更好地声明您的意图

它增加了代码评审中的WTF/min。

在C++03中,使用std::string存储字节数据数组不是一个好主意。按照标准,std::string不具有连续存储数据的能力。C++11修复了这一问题,因此它的数据必须是连续的。

因此,在C++03中这样做是不起作用的。除非您亲自审查了std::string的C++标准库实现,以确保它是连续的。

无论哪种方式,我都建议vector<char>。通常,当您看到string时,您希望它是一个…字符串。你知道,以某种形式编码的字符序列。vector<char>表明它不是一个字符串,而是一个字节数组。

除了连续存储和代码清晰度问题外,我在尝试使用std::string保存原始字节时遇到了一些相当隐蔽的错误。

他们中的大多数人都集中在尝试在与C库接口时将char字节数组转换为std::string。例如:

std::string password = "password";
std::cout << password.length() << std::endl; // prints 4, not 9

也许你可以通过指定长度来解决这个问题:

std::string password("password", 0, 9);
std::cout << password.length() << std::endl; // nope! still 4!

这可能是因为构造函数希望接收C字符串,而不是字节数组。也许有更好的方法,但我最终得到了这个:

std::string password("pass0word", 0, 9);
password[4] = '';
std::cout << password.length() << std::endl; // hurray! 9!

有点笨重。谢天谢地,我在单元测试中发现了这一点,但如果我的测试向量没有空字节,我就会错过它。使这种情况变得阴险的是,上面的第二种方法将很好地,直到数组包含一个空字节。

到目前为止,std::vector<uint8_t>看起来是一个不错的选择(感谢J.N.和Hurkyl):

char p[] = "password";
std::vector<uint8_t> password(p, p, p+9); // :)

注意:我还没有尝试过使用std::string的迭代器构造函数,但这个错误很容易发生,甚至值得避免这种可能性。

经验教训:

  • 具有包含测试向量的空字节的测试字节处理方法
  • 当使用std::string来保存原始字节时要小心(我会说避免)

使用std::string存储文本文件中的字符。这样,您就可以放心,字符编码是为您正确完成的。

使用std::vector<std::byte>存储二进制文件中的原始字节。这将防止意外的类型转换,并确保安全的数据操作。数据的精确表示是至关重要的,并传达意图。

最新更新