gzstream lib打开不存在的文件

时间:2014-11-22 11:21:19

标签: c++ multiple-inheritance zlib libz

我正在尝试在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相同。

因为如果文件不存在,初始化后第一个变量为good()返回true。 AFAIK是因为两个祖先std :: ios。

我想知道它真的是一个错误,为什么它还没有修复!

2 个答案:

答案 0 :(得分:3)

根据[lib.istream],C ++标准将名称std::istream定义为[lib.iostream.format]中std::basic_istream<char>的typedef,它实际上是从std::basic_ios<char>派生的。 另一方面,gzstreambase实际上是从std::ios派生的,std::basic_ios<char>在[lib.iostream.forward]中定义为std::ios的typedef。因此,两个继承分支都具有与std::basic_ios<char>(又名std::ios)的虚拟继承关系。

如果您的标准库实现没有被破坏,您不应该在igzstream中获得两个std::ios子对象,但通过更改基类初始化的顺序来声明基类虚拟会产生进一步的后果。

class igzstream : public gzstreambase, public std::istream

首先初始化虚拟基类(甚至是间接类),因此首先初始化std::ios_base,然后初始化gzstreambase(自身的非虚基类)。然后,非虚拟基类按从左到右的顺序进行初始化,首先是std::istream,然后是std::ios

class igzstream : public gzstreambase, virtual public std::istream

首先初始化虚拟基类(甚至是间接类),因此首先初始化std::ios_base,然后初始化std::istream(自身的非虚基类)。然后初始化std::ios,因为它仍然是另一个虚拟基类,但需要gzstreambase,最后需要std::istream

考虑到这一点,您可以确定来自std::istream的虚拟派生似乎是非常糟糕的主意,因为igzstream的构造函数将其名为buf的gzstreambuf成员的地址传递给

问题的原因可能是gzstreambase(consth char *, int)调用std::ios::init(),而std::istream构造函数的行为 as-if 它的行为相同,根据[ lib.istream.cons。记录函数std::ios::init以初始化流状况良好。因此,如果在gzstreambase对象之后初始化istream子对象,则ios基础对象的第二个init应该确实清除错误标志。这实际上看起来像gzstream库中的一个错误。获得正确的施工顺序(gzstreambuf首先,istream第二,然后尝试打开文件)似乎是一个完全不平凡的问题。原始版本有“gzstreambuf,open,istream”,其中istream破坏了开放失败,而你提出的修复有“istream,gzstreambuf,open”,其中istream获取尚未构建的streambuf的地址。

解决方法是不使用gzstream的开放构造函数,但我会考虑修复开放构造函数的一个很好的解决方案,并在我得到结果后立即编辑答案。

根据您的要求,多个初始化调用都可以(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派生实现而不会出现问题。

我在这种情况下看到的唯一解决方案是删除执行open的gzstreambase构造函数,并在igzstream和ogzstream构造函数中放置open调用(从而复制调用open)。这样,可以依赖于在istream / ostream构造函数中调用init一次且只调用一次。

答案 1 :(得分:0)

不更改库而可能的解决方法是使用默认构造函数,然后再打开文件。

示例:

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
相关问题