2014-11-22 2 views
1

xcode 6.1, libz.1.dylib에서 ios 개발을 위해 gzstream 1.5를 사용하려고합니다.gzstream lib에서 기존 파일을 열 수 없음

이 라이브러리는 꽤 오래 전에 작성되었습니다.

나는

class igzstream : public gzstreambase, public std::istream 

이 ogzstream에 대한

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

동일해야 것으로 나타났습니다.

파일이 없으면 첫 번째 변형은 초기화 후 good()에 대해 true를 반환합니다. AFAIK 왜냐하면 그것은 두 조상 std :: ios 때문입니다.

정말 버그입니까, 아직 해결되지 않은 이유가 궁금합니다!

답변

2

은 C++ 표준 사실상 [lib.istream]에있어서, std::basic_ios<char>로부터 유도된다 lib.iostream.format]에 std::basic_istream<char>의 타입 정의로 std::istream 이름을 정의한다. 한편, gzstreambase은 실질적으로 std::ios에서 파생되며, std::basic_ios<char>의 typedef로 [lib.iostream.forward]에 정의되어 있습니다. 따라서 두 상속 브랜치는 모두 std::ios (일명 std::basic_ios<char>)과의 가상 계승 관계를가집니다.

표준 라이브러리 구현이 손상되지 않은 경우 igzstream에서 두 개의 std::ios 하위 객체를 가져 오지 말고 기본 클래스 가상을 선언하면 기본 클래스 초기화 순서를 변경하여 추가 결과가 발생합니다.

class igzstream : public gzstreambase, public std::istream

가상 기본 클래스 (심지어 간접적 인 것들) 그래서 std::ios 차례로 std::ios_base (자체의 가상이 아닌 기본 클래스)를 초기화하는 초기화 할 첫 번째, 첫 번째 초기화됩니다. 그런 다음 비 가상 기본 클래스가 왼쪽에서 오른쪽 순서로 초기화되므로 gzstreambase을 먼저 지정한 다음 std::istream을 먼저 만듭니다.

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

가상 기본 클래스 (심지어 간접적 인 것들) 그래서 std::ios 차례로 std::ios_base (자체의 가상이 아닌 기본 클래스)를 초기화하는 초기화 할 첫 번째, 첫 번째 초기화됩니다. 그런 다음 std::istream은 여전히 ​​초기화되지만 다른 가상 기본 클래스 인 경우 std::ios이 필요하고 마지막으로 gzstreambase이 필요합니다. std::istream에서 가상 유도가 생각 아주 나쁜 처럼 보인다 igzstream의 생성자가 전에 std::istream 객체의 생성자 buf를 호출의 gzstreambuf 멤버의 주소를 전달하기 때문에 마음에두고

, 당신은 확인할 수 있습니다 상속 된 멤버 buf가 초기화되었습니다.

아마 문제의 원인은 gzstreambase(consth char *, int) 전화 std::ios::init()하고 std::istream 생성자 을 동작한다는 것입니다 AS-경우 그것을 않습니다 같은, [lib.istream.cons]에 따라. std::ios::init 함수는 스트림을 양호한 상태로 초기화하기 위해 문서화되어 있습니다. 따라서 istream 하위 객체가 gzstreambase 객체 다음에 초기화되면 ios 기본 객체의 두 번째 초기화가 실제로 오류 플래그를 지워야합니다. 실제로 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을 여러 번 호출하면 메모리 누수가 발생하고 Microsoft에서 사용하는 I/O 라이브러리를 제공하는 Dinkumware는 표준에서 여러 호출에 동작을 지정하지 않으므로 정의되지 않은 동작이라고 주장합니다.

실제 휴대용 동작의 경우 은 반복적으로 초기화를 호출하지 않습니다.. 그러나 이것은 gzstream에서 일어나는 일입니다. 이것은 실제로 C++에서와 같이 여러 상속의 반대자가 옳다고 여겨지는 상황 중 하나입니다. 은 "istream 인터페이스"를 제공 할 수 있도록 std :: istream을 상속해야하지만 다른 한편으로는 이 필요하지 않습니다.은 생성자가 원하지 않는 일을하기 때문에 std :: istream을 상속하지 않습니다. . std :: istream이 "단지 인터페이스"라면, 문제없이 gzstreambase에서 구현을 파생시키는 것과 함께 구현할 수 있습니다.

이 경우에 볼 수있는 유일한 해결책은 gzstreambase 생성자를 열고 수행하고 open 호출을 igzstream 및 ogzstream 생성자에 둡니다 (따라서 호출을 open에 복사하는 것입니다). 이 방법은 istream/ostream 생성자에서 한 번만 호출되는 init에 의존 할 수 있습니다.

+0

마이클이 여기에 있습니다. 주어진 모든 설명. 고맙습니다! – Erdemus

관련 문제