在 C++ 中通过迭代器将向量写入二进制文件的正确方法
Posted
技术标签:
【中文标题】在 C++ 中通过迭代器将向量写入二进制文件的正确方法【英文标题】:The right way to write a vector to a binary file by iterator in C++ 【发布时间】:2021-08-24 19:35:06 【问题描述】:我已经搜索了很多此类问题,但没有得到满意的答案。
我正在研究使用 C++ 中的 ofstream::write 方法将矢量容器写入二进制文件的函数。
#include <vector>
#include <fstream>
typedef std::vector<unsigned char> byteArray;
byteArray data;
data.push_back('a');
data.push_back('b');
data.push_back('c');
data.push_back('d');
std::ofstream fout("out_file", std::ios::out | std::ios::trunc | std::ios::binary);
// I know the right way should be as following:
fout.write((char *)&data[0], data.size());
// But what I cannot understand is why the following expression is wrong, since gcc compiler says
// invalid cast from type ‘__gnu_cxx::__normal_iterator<unsigned char*, std::vector<unsigned char> >’ to type ‘char*’
for(auto iter = data.begin(); iter != data.end(); iter++)
fout.write((char *)iter, 1);
fout.close();
据我了解,迭代器 iter 是一个指针,它指向向量“数据”中的一个元素。所以我认为(char *) iter会将底层数据类型重新解释为char,那么它应该满足fout.write的参数要求。但实际上,情况并非如此。我也很困惑 gcc 说 iter 是一种 iterator
我怎么了?非常感谢您的帮助。
【问题讨论】:
“据我了解,iterator iter 是一个指针”。否。std::vector::iterator
是未指定的类型。如果需要指针,则需要&*iter
。
不要对类型做出假设。即使您理解正确,只要行为保持不变,实际类型可能会随着时间而改变。这就是为什么C-Cast
如此危险,它会因为假设而隐藏错误。
我不会假设数组总是每个字符包含 1 个字节。如果有人更改了数组的类型并忘记更新写入,它将默默地中断。 fout.write((char *)&data[0], data.size() * size_of(byteArray[0]);
Martin York 是对的,我应该在 fout.write 函数中添加 size_of(byteArray[0])。万分感谢。 :) 对于 C++,我应该还有很长的路要走。
【参考方案1】:
据我了解,iterator iter 是一个指针
事实并非如此。 std::vector::iterator
是未指定的类型。
您可以期望它具有一些类似指针的属性,但您不应假设它可能是什么特定类型。
因为您需要一个指针,所以取消对迭代器的引用并获取该结果的地址。那是一个指针。
fout.write((char *)&*iter, 1);
更好的是,使用 C++ 转换而不是难以跟踪的 C 转换。
fout.write( static_cast<char*>(&*iter), 1 );
甚至更安全(Martin York 始终是一颗珍贵的宝石)——不要假设包含类型的大小。未来可能会改变。此更改不会增加任何开销。
fout.write( static_cast<char*>(&*iter), size_of(byteArray[0]) );
【讨论】:
最好不要假设迭代器指向一个字符。 这很好用!似乎我仍然太天真,无法理所当然地将迭代器作为指针。 :-) "取消引用迭代器并获取该结果的地址" - 请注意,如果类型重载&
运算符,则必须使用 std::addressof()
来获取地址,例如:std::addressof(*iter)
@RemyLebeau 总。但是是真的。但是很恶心。【参考方案2】:
指针可以用作迭代器,但迭代器不必是指针。
通过提供取消引用operator*()
、递增operator++()
等操作,迭代器的行为或多或少类似于指针,参见例如要求LegacyInputIterator
虽然具体定义会随着时间而变化,但请参阅 std::input_or_output_iterator 了解 C++20 中的定义。
【讨论】:
以上是关于在 C++ 中通过迭代器将向量写入二进制文件的正确方法的主要内容,如果未能解决你的问题,请参考以下文章