gzstream 库打开不存在的文件
gzstream lib opening not existing file
我正在尝试在xcode 6.1,libz.1.dylib下使用gzstream 1.5进行iOS开发。
这个库是很久以前写的。
我发现
class igzstream : public gzstreambase, public std::istream
应该是
class igzstream : public gzstreambase, public virtual std::istream
ogzstream也是如此。
因为如果文件不存在,第一个变体在初始化后返回 true 表示 good()。AFAIK 这是因为两个祖先 std::ios。
我想知道它真的是一个错误,为什么它还没有修复!
C++标准将名称std::istream
定义为 [lib.iostream.format] 中 typedef 的 std::basic_istream<char>
,根据 [lib.istream] 的说法,它实际上是从std::basic_ios<char>
派生出来的。另一方面,gzstreambase
实际上是从 std::ios
派生而来的,在 [lib.iostream.forward] 中定义为 std::basic_ios<char>
的 typedef。因此,两个继承分支都与std::ios
(又名std::basic_ios<char>
)具有虚拟继承关系。
如果你的标准库实现没有被破坏,你不应该在 igzstream 中获取两个std::ios
子对象,但是通过更改基类初始化的顺序,声明基类 virtual 会产生进一步的后果。
类 IGZSTREAM : public gzstreambase, public std::istream
虚拟基类(甚至是间接基类)首先初始化,因此首先初始化std::ios
基类,进而初始化std::ios_base
(自身的非虚拟基类)。然后按从左到右的顺序初始化非虚拟基类,因此先gzstreambase
,然后std::istream
。
类 IGZSTREAM: public gzstreambase, virtual public std::istream
虚拟基类(甚至是间接基类)首先初始化,因此首先初始化std::ios
基类,进而初始化std::ios_base
(自身的非虚拟基类)。然后初始化std::istream
,因为它仍然是另一个虚拟基类,但需要std::ios
,最后gzstreambase
。
考虑到这一点,您可以确定从std::istream
虚拟派生似乎是一个非常糟糕的主意,因为 igzstream 的构造函数在继承的成员 buf 初始化之前将其名为 buf 的 gzstreambuf 成员的地址传递给std::istream
对象的构造函数。
根据 [lib.istream.cons] 的说法,您的问题的原因可能是gzstreambase(consth char *, int)
调用std::ios::init()
,并且std::istream
构造函数的行为就像它做同样的事情一样。记录了函数std::ios::init
以初始化状况良好的流。因此,如果在 gzstreambase 对象之后初始化 istream 子对象,则 ios base 对象的第二个 init 确实应该清除错误标志。这实际上看起来像是gzstream库中的一个错误,确实。获得正确的构造顺序(首先是gzstreambuf,其次是istream,然后尝试打开文件)似乎是一个完全不平凡的问题。原始版本有"gzstreambuf,open,istream",其中istream破坏了打开失败,而您提出的修复程序有"istream,gzstreambuf,open",其中istream获取尚未构建的streambuf的地址。
解决方法是不使用 gzstream 的开放构造函数,但我会考虑一个好的解决方案来修复打开构造函数,并在得到结果后立即编辑答案。
根据您询问的对象,多个 init 调用是可以的(通常对 http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-closed.html#135 的解释)或未定义的(http://article.gmane.org/gmane.comp.lib.boost.devel/235659)。在Microsoft编译器上,多次调用 init 会导致内存泄漏,Dinkumware(提供 Microsoft 使用的 I/O 库)坚持认为该标准没有指定多次调用的行为,因此它是未定义的行为。
因此,对于实际的便携式行为,请勿重复调用 init。然而,这就是gzstream中发生的事情。这实际上是反对多重继承的情况之一,因为C++似乎是对的。你确实需要继承 std::istream 才能提供"istream 接口",而另一方面,你不需要继承 std::istream,因为它的构造函数会做你不想要的事情。如果 std::istream "只是一个接口",你可以毫无问题地实现它,同时从 gzstreambase 派生实现。
在这种情况下,我看到的唯一解决方案是删除执行打开的gzstreambase构造函数,并在igzstream和ogzstream构造函数中放置打开调用(从而复制对打开的调用)。这样,可以依赖 init 被调用一次,并且在 istream/ostream 构造函数中只调用一次。
在不更改库的情况下,一种可能的解决方法是使用默认构造函数并稍后打开文件。
例:
igzstream noErrorFile("nonExistentFile"); // no error
cout << "error initializing with non-existent file " << noErrorFile.fail() << endl;
igzstream errorFile;
errorFile.open("nonExistentFile"); // error
cout << "error opening with non-existent file " << errorFile.fail() << endl;
结果:
error initializing with non-existent file 0
error opening with non-existent file 1
- 如何将 pls 文件保存在 QMediaPlaylist 而不是 m3u 中
- CMake 生成的程序无法在 Windows 上链接:尝试链接到不存在的文件
- 在不存在的目录中打开文件,C 与 C++
- C++ Linux 可执行文件一直尝试使用不存在的库
- 从文本文件中读取时,即使不存在,也会找到额外的字符(例如"@")?
- 如果C 中不存在,如何创建文件夹
- 尝试使用 wxWidgets 从 zip 打开不存在的文件时无法捕获的异常
- 打开文件,如果不存在,则创建,确定是否创建
- ifstream不读取文件中存在的`0a`字节
- ifstream::is_open 返回 true,即使该位置不存在文件也是如此
- 复制文件时是否可以自动创建不存在的目录?
- 如何从C 中的HDF5文件中读取属性名称和数据集名称,在这里我不知道HDF5文件中存在什么属性
- 打开不存在的文件时如何使流构造函数失败?
- 如果文件中不存在qt5中的文件,如何原子创建该文件
- C++仅当文件不存在时才打开文件进行写入
- 如果文件不存在,ifstream 会创建文件
- WinAPI - 如果文件不存在,则创建.ini文件
- 即使输入文件不存在,也会继续创建输出文件?编辑****
- 如何仅在不创建文件的情况下创建文件'不存在
- 当INI文件不存在时,使用Boost属性树读取INI文件