C++ ifstream::read() 和 C 数组

4
似乎普遍认为C数组不好用,使用更智能的替代方案,如向量或C++字符串是正确的选择。这里没有问题。
话虽如此,为什么ifstreamread()成员将数据输入到char*中... 问题是:我能否仅使用STL将数据输入到字节向量中?
相关的奖励问题:您是否经常检查ios::badbitios::failbit,特别是如果在该范围内使用动态分配的C字符串?您会在catch()中进行C字符串的释放吗?
感谢您的阅读。
2个回答

2
说了这么多,为什么 ifstream 的 read() 成员函数要输入数据到 char* 中呢?这是一种设计选择,不一定是最聪明的选择。
问题是:我能以某种方式输入到字节向量吗? std::vector<char> 的底层存储被保证是连续的(即单个内存块),所以可以。要使用 ifstream::read,您必须(a)确保向量的大小足够大(使用 .resize() - 而不是 .reserve()!这是因为向量没有办法知道您正在读入其未使用的 capacity 的数据并更新其 size),然后(b)获取指向向量起始元素的指针(例如使用 &v.front()&(v[0]))。
如果您不想预先调整向量的大小,则可以使用更高级的技术,涉及迭代器类型和标准库算法。这些具有优势,可以轻松地将整个文件读入向量,而无需首先检查文件长度(检查文件长度的标准技巧可能不如您想象的那样可靠!)。
看起来像这样:
#include <iterator>
#include <algorithm> // in addition to what you already have.
// ...
std::ifstream ifs;
std::vector v;
// ...
std::istreambuf_iterator<char> begin(ifs), end;
std::copy(begin, end, std::back_inserter(v));
std::string可以像字节向量一样使用,当然,它们并不相同。但是你可以使用std::back_inserter函数来实现完全相同的功能,该函数足够智能,可以为任何提供了.push_back()方法的类型创建适当的迭代器类型,这包括stringvector。这就是模板的魔力:)

仅使用C++标准库?

我有点困惑。我认为我们在谈论C++标准库。你所说的STL是什么?

相关的奖励问题:你经常检查ios::badbit和ios::failbit吗?

不会,我通常会以一种可以直接检查读取操作结果的方式编写代码。请参见http://www.parashift.com/c++-faq-lite/input-output.html#faq-15.4获取示例/讨论。

尤其是在该范围内使用动态分配的C字符串时?

总体而言,这是个糟糕的主意。

你是否在catch()中释放了C字符串?

而且必须处理这种情况是主要原因之一。这不容易做到正确。但我希望你意识到捕获异常和检查ios::bits是两件完全不同的事情。尽管你可以配置流对象抛出异常,而不仅仅是设置标志位 :)


2

你可以直接读取已分配的向量(我无法从这里编译,因此可能会有错别字或转置参数等...),但是这个想法是正确的。

vector<char> data;
data.resize(100);

// Read 100 characters into the storage of data
thing.read(&data[0], 100);

在创建时,您还可以使用 explicit vector ( size_type n, const T& value= T(), const Allocator& = Allocator() ); 指定向量的大小。请注意,最后两个参数具有默认值,因此您可以只使用 vector<char> data(100); - Dan
@JohnB 看起来有点hackish,但是我想起了[]被重载了。感谢你的回复。 - catfish_deluxe_call_me_cd
是的,我知道你的意思 :) 但这是获取指向数据开头的指针的正确方法 :) - jcoder
构造函数ifstream接受const char*文件名而不是const std::string&,这与之前的情况类似。我猜测STL的设计者不想在库之间引入太多依赖关系。 - user729124
1
获取数据开头的指针有一个正确的方法。一些人更喜欢使用&data.front(),并且对此有一个相当不错的审美论点。 - Karl Knechtel

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