为什么std::fstream使用char*?

3

我正在编写一个小程序,它以16个字节为一组从二进制文件中读取字节(请不要问为什么),对其进行修改,然后将其写入另一个文件。

fstream::read 函数读取到一个 char * 缓冲区中,我最初传递给了一个类似下面的函数:

char* modify (char block[16], std::string key)

修改操作是在 block 上完成的,此后返回该块。在浏览 SO 的帖子时,我意识到使用 std::vector<char> 可能是一个更好的想法。我的下一个担心是如何将 char * 转换为 std::vector<char>。再一次,SO 给了我答案
但现在我想知道的是:如果使用 std::vector<char> 而不是 char* 是这么好的想法,为什么 fstream 函数中还要使用 char* 呢?
另外,将来自 fstreamchar* 转换为 std::vector<char> 是否是一个好主意呢?
编辑:我现在意识到由于 fstream::read 用于直接向对象写入数据,所以 char * 是必需的。现在我必须修改我的问题。首先,为什么没有为 fstream::read 提供重载函数?其次,在我编写的程序中,哪个选项更好?

1
不确定这是否有帮助,但您可以直接使用类似 .read(&vect[0], 16)(或者如果您使用的是C++11,则使用.read(vect.data(), 16))将其读入到 std::vector 中,以避免使用 char* 中间人。只需确保使用 .resize 分配足够的数据空间即可。 - Xymostech
1
我认为并非所有的缓冲区都是std::vector<char>(有时你会得到一个char*库来读取数据)。如果std::fstream强制你使用std::vector<char>而不允许使用许多变体(原始数组,std::array等),那就有点奇怪了。此外,有时您需要直接将数据读取/反序列化到类型中(如int),在这种情况下,std::vector<char>只是...奇怪。 - Cornstalks
@Cornstalks: 很好。但是是否可以有重载的构造函数呢? - Vivek Ghaisas
1
@VivekGhaisas:“传递指向std::vector的指针是否安全?”只要它已经被预先调整大小,使用指针进行二进制操作没有任何问题-那些读/写函数不需要知道正在写入的对象,只需要一个地址和字节数。如果您希望在自己的应用程序中获得更多的安全性,请编写一个覆盖层-例如,为您的对象编写序列化例程:然后只有一个中央位置需要处理地址和sizeof - Tony Delroy
1
@VivekGhaisas:对你来说,vector<double> 看起来很有用。对其他人来说,deque<float> 很有用。很快就会有很多 read() 的重载,很难看出 fstream 类做了什么...;-) - Tony Delroy
显示剩余5条评论
2个回答

1
fstream()函数允许您使用char*,因此您可以将它们指向任意预分配的缓冲区。 std::vector<char>可以调整大小以提供适当的缓冲区,但它将位于堆上,并且涉及到分配成本。有时候,您可能想要读取或写入数据到内存中的特定位置 - 即使是在共享内存中 - 而不是接受vector恰好分配的堆内存。此外,您可能希望在没有包含vector头文件的情况下使用fstream...能够避免不必要的包含很好,因为它会减少编译时间。

由于您的缓冲区始终为16字节大小,因此最好将它们分配为适当拥有对象(如果存在)中的char [16]数据成员,或者在堆栈上(即某些函数的局部变量)。

vector<>更有用的是当替代选择为堆分配时——无论是因为大小在编译时未知,还是特别大,或者您想要更灵活地控制内存生命周期。当您特别需要一些其他向量功能时,例如更改元素数后,对字节进行排序等,它也非常有用——似乎您不会想做任何这样的事情,因此向量会引起阅读代码的人关于您将为没有好处的目的而做什么的疑问。尽管如此,char[16]vector的选择(根据您的声明要求)似乎更多是品味问题,而不是客观利益。


1
可以说,为了更有用,它应该是 void* - Ben Voigt
1
@VivekGhaisas:是的 - 使用 char*,您可以指向内存中的任何位置,而如果它期望使用 std::vector<char>std::string,那么您必须接受额外数据成员(记录开始/结束、容量等)在这些对象中的开销,它们选择分配内存的方式以及它们管理生命周期的方式。灵活性要少得多。从您问题的描述中,char[16] 听起来很好:它是您数据需求的最直接表示。 - Tony Delroy
@TonyD:谢谢,那很有道理。 - Vivek Ghaisas
1
@BenVoigt:同意,不过在char*上进行算术运算有一定的(危险的)便利性。 - Tony Delroy
1
@BenVoigt:实际上,void*太危险了,因为你可以传递任何旧事物的地址。char*强制调用者理解他们所指向的东西需要能够被视为字节数组(标准布局)。 - GManNickG
显示剩余4条评论

1

如果要与向量一起使用,请勿传递向量的指针。相反,传递指向向量内容的指针:

vector<char> v(size);
stream.read(&v[0], size);

考虑到程序的功能,您是否建议我使用std::vector<char> - Vivek Ghaisas
@Vivek:不需要动态大小或交换的话,就不需要。 - Ben Voigt
我确实需要交换单个字符的值,但我不需要任何动态内容。所以最终,是使用std::vector<char>还是char* - Vivek Ghaisas
@Vivek:如果您不需要动态大小,char block[16]; stream.read(block, 16); 应该可以正常工作。 - Ben Voigt

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