4

几天前,我决定编写一个streambuf可以使用mmap和预读的子类会很有趣。我查看了我的 STL (SGI) 如何实现filebuf并意识到它basic_filebuf包含一个FILE*. 所以继承自是不可能basic_filebuf的。

所以我继承自basic_streambuf. 然后我想将我的绑定mmapbuf到一个 fstream。

我认为我唯一要做的就是复制filebuf...的隐式接口,但这是一个明显的错误。在 SGI 中,basic_fstream拥有一个basic_filebuf. 无论我是否调用basic_filestream.std::::ios::rdbuf( streambuf* ),文件流都会完全忽略它并使用它自己的filebuf.

所以现在我有点困惑......当然,我可以创建自己的mmfstream,这将是精确的复制/粘贴,fstream但听起来真的不是面向 DRY。

我无法理解的是:为什么这样fstream做与 紧密耦合filebuf,以至于除了 a 之外不能使用任何东西filebuf分离流和缓冲区的全部意义在于可以使用具有不同缓冲区的流。

解决方案:

=>filestream应该依赖filebuf. 也就是说, fstream 应该由 streambuf 类模板化。这将允许每个人都可以向 a 提供自己的 streambuf 子类,fstream只要它实现了filebuf的隐式接口。问题:我们无法添加模板参数,fstream因为它会在fstream用作模板模板参数时破坏模板选择器。

=>filebuf应该是一个没有任何附加属性的纯虚拟类。这样人们就可以从它继承而不携带它所有的 FILE* 垃圾。

你对这个主题的想法?

4

4 回答 4

11

在 IO 流的设计中,大多数实际流的功能(与流缓冲区的功能相反)是在 、 和它们的基类中实现std::basic_istreamstd::basic_ostream字符串和文件流类或多或少只是方便的包装器,它们确保实例化具有正确类型缓冲区的流

如果你想扩展流,你几乎总是想提供你自己的流缓冲类,你几乎不需要提供你自己的流类。.

一旦你有了自己的流缓冲区类型,你就可以让它成为你碰巧拥有的任何流对象的缓冲区。std::basic_istream或者您从,派生您自己的类std::basic_ostreamstd::basic_iostream它会实例化您的流缓冲区并将其传递给它们的基类。
后者对用户来说更方便,但需要您为缓冲区的实例化编写一些样板代码(即流类的构造函数)。

回答您的问题:文件流和文件缓冲区耦合得如此紧密,因为前者的存在只是为了简化后者的创建。使用文件流可以轻松设置所有内容。
使用您自己的流类来包装您自己的流缓冲区的构造应该不是问题,因为无论如何您都不应该传递文件流,而只是(引用)基类。

于 2010-06-07T13:18:00.880 回答
2

fstream本身并不是一个大类。它继承自basic_stream以提供对所有<<and>>操作的支持,包含一个steambuf必须初始化的专门化的,以及相应的构造函数以将参数传递给streambuf构造函数。

从某种意义上说,您所写的有关模板化解决方案的内容是可以的。但basic_stream也可以导出成一个tcp_stream例子。在那种情况下, 的构造函数fstream有点没用。因此,您需要提供一个新tcpstream类,继承自basic_stream正确的参数,以便构造函数能够创建tcp_stream. 最后,您不会使用fstream. 创建这个新tcpstream函数只需编写 3 或 4 个函数。

最后,你会从fstream类派生而没有任何真正的理由。这会在类层次结构中增加更多的耦合,不必要的耦合。

于 2010-06-07T12:53:36.720 回答
2

查看Boost.Iostreams库中的mapped_file 。我自己从未使用过它,但它似乎已经可以满足您的需求。

编辑:哎呀,重读你的问题,我看到你这样做是为了好玩。或许您可以从 Boost.Iostreams 中汲取灵感?

于 2010-06-07T13:45:43.540 回答
1

的全部意义std::fstream在于它是基于 _F _ilestd::stream。如果你想要一个std::stream由你支持的普通mmstreambuf,那么你应该创建一个mmstreambuf并将它传递给std::stream::stream(std::streambuf*)

于 2010-06-07T13:03:46.267 回答