2013-07-15 2 views
2

부스트 직렬화에 약간의 문제가 있습니다. BOOST_CLASS_EXPORT 및 BOOST_CLASS_EXPORT_IMPLEMENT를 사용하여 기본 클래스 포인터를 통해 파생 클래스 포인터를 직렬화하는 방법을 보여주는 많은 예제가 있습니다. 이것은 잘 작동하고 전혀 문제가 없습니다.역 참조 기본 클래스 포인터를 통한 부스트 직렬화

그러나 반대쪽의 직렬화를 다시 포인터로 가져와 부스트하면 직렬화 된 개체의 새 인스턴스가 만들어지기 때문에 포인터를 직렬화하고 싶지 않습니다.

역 참조 된 포인터를 직렬화 한 다음 문제없이 기존 개체 인스턴스에 대해 다시 deserialize 할 수 있으며 새 인스턴스가 만들어지지 않습니다. 그러나 역 참조 된 포인터가 기본 클래스 위에있을 때 포인터를 통해 직렬화 할 때 파생 클래스는 예상대로 직렬화되지 않습니다.

근무 예 :

Class A; 
Class B : public A; 

A* baseClass = new B(); 
ar << baseClass // works perfectly 

작동하지 예 :

Class A; 
Class B : public A; 
A* baseClass = new B(); 
ar << *baseClass; // only A is serialized 

내가 같은 파생 클래스를 통해 간단한 일련의 순차적으로 작업을 얻을 수 있습니다 :

B* derivedClass = new B(); 
ar << *derivedClass; // works fine 

그러나 모든 참조 내 구조에는 기본 클래스 유형이 있습니다. 또한 deserializing 할 때 새 객체를 인스턴스화 할 필요가 없으므로 포인터를 직렬화 할 수 없으며 기존 인스턴스 위에 내용을 "덮어 씁니다".

포인터를 직렬화하고 기존 인스턴스를 역 직렬화하려고 시도했지만 올바르게 작동하지 않습니다. 나는 기존의 인스턴스를 통해 직렬화 말할 때, 내 말은 :

A* baseClass = new B(); 
// baseClass is used in the program and in a given moment, its contents must be overwrite, so: 
ar >> *baseClass; 

내가 말했듯이 직렬화 복원 할 때, 나는 BaseClass로의 새로운 인스턴스를 필요가 없습니다. 그래서,이 방법을 사용할 수있는 방법이 있습니까?

+0

안녕하세요, 조금 늦었습니다.하지만 방금이 질문을 발견했습니다. 나는 똑같은 문제에 직면하고있다. 나는이 문제가 참조로 해결 될 수 있다고 생각했지만, 기본 클래스에 대한 참조를 통해 직렬화하는 것은 나를 위해 작동하지 않는다. 이 문제를 해결할 수 있습니까? – TomasG

+0

@TomasG 님이 지적한 해결책을 마침내 사용했습니다. 기본적으로 직렬화 및 직렬화 desalialize 가상 함수를이 방식으로 직렬화 할 클래스에 추가 구성됩니다. 다행히도 그들은 거의 없습니다. –

+1

답변을 주셔서 감사합니다, 동정 거기에 더 우아한 솔루션입니다. – TomasG

답변

1

나는 당신과 같은 문제를 만났습니다! 그래서 문제를 해결할 수있는 방법을 제공하는 부스트의 문서를 보았습니다. 클래스 D를 정의하여 파생 객체를 관리하고 ar.register_type을 사용하여 abc와 비교합니다 클래스와 같은 :

class base { 
    ... 
}; 
class derived_one : public base { 
    ... 
}; 
class derived_two : public base { 
    ... 
}; 
main(){ 
    ... 
    base *b; 
    ... 
    ar & b; 
} 

저장할 때 어떤 종류의 개체를 저장해야합니까? 로드 할 때 어떤 종류의 객체를 만들어야합니까? 그것은 derived_one, derived_two, 또는 base일까요?

직렬화 된 개체의 종류는 기본 클래스 (이 경우 기본)가 폴리 모픽인지 여부에 따라 달라집니다. base가 다형성이 아닌 경우, 즉 가상 함수가없는 경우 기본 유형의 객체가 직렬화됩니다. 파생 된 클래스의 정보는 손실됩니다. 이것이 원하는 경우 (일반적으로 그렇지 않은 경우) 다른 노력은 필요하지 않습니다.

기본 클래스가 다형성 인 경우 가장 많이 파생 된 유형의 객체 (이 경우 derived_one 또는 derived_two)가 직렬화됩니다. 어떤 유형의 객체가 직렬화되어야하는지에 대한 질문은 라이브러리에 의해 (거의) 자동으로 처리됩니다.

시스템은 해당 클래스의 객체를 처음으로 아카이브 할 때 각 클래스를 아카이브에 "등록"하고 일련 번호를 할당합니다. 다음 번에 해당 클래스의 객체가 동일한 아카이브에서 직렬화되며이 숫자는 아카이브에 기록됩니다. 따라서 모든 클래스는 아카이브 내에서 고유하게 식별됩니다.아카이브가 다시 읽혀지면 각각의 새로운 순차 번호는 읽을 클래스와 다시 연관됩니다. 이것은로드시 작성된 클래스 정수 테이블이 save에서 빌드 된 클래스 정수 테이블과 동일하도록 저장 및로드 중에 "등록"이 발생해야 함을 의미합니다. 사실, 전체 직렬화 시스템의 핵심은 항상 동일한 순서로 저장되고로드된다는 것입니다. 여기에는 "등록"이 포함됩니다. B가 이전 클래스 derived_one 또는 derived_two 관련되어 클래스 ID (아카이브에) 고유 앞에는 판독

main(){ 
    derived_one d1; 
    derived_two d2: 
    ... 
    ar & d1; 
    ar & d2; 
    // A side effect of serialization of objects d1 and d2 is that 
    // the classes derived_one and derived_two become known to the archive. 
    // So subsequent serialization of those classes by base pointer works 
    // without any special considerations. 
    base *b; 
    ... 
    ar & b; 
} 

.

파생 클래스가 위에서 설명한 것처럼 자동으로 "등록"되지 않은 경우 직렬화가 호출 될 때 unregistered_class 예외가 throw됩니다.

파생 클래스를 명시 적으로 등록하여 해결할 수 있습니다. 모든 아카이브는 다음과 같은 템플릿을 구현하는 기본 클래스에서 파생됩니다

template<class T> 
register_type(); 

그래서 우리의 문제는 단지뿐만 아니라 서면에 의해 해결 될 수있다 :

main(){ 
    ... 
    ar.template register_type<derived_one>(); 
    ar.template register_type<derived_two>(); 
    base *b; 
    ... 
    ar & b; 
} 

주 직렬화 기능이 저장 사이에 분할되는 경우 있음 두 기능 모두 등록을 포함해야합니다. 이것은 저장 및 해당로드를 동기화 상태로 유지하는 데 필요합니다.

당신은 또한 사용할 수 있습니다

#include <boost/serialization/export.hpp> 
... 
BOOST_CLASS_EXPORT_GUID(derived_one, "derived_one") 
BOOST_CLASS_EXPORT_GUID(derived_two, "derived_two") 

main(){ 
    ... 
    base *b; 
    ... 
    ar & b; 

} 매크로 BOOST_CLASS_EXPORT_GUID는 클래스 리터럴 문자열을 연결합니다. 위의 예제에서 클래스 이름의 문자열 렌더링을 사용했습니다. 그러한 "내 보낸"클래스의 객체가 포인터를 통해 직렬화되고 다른 방식으로 등록이 해제되면 "내보내기"문자열이 아카이브에 포함됩니다. 아카이브가 나중에 읽혀질 때 문자열 리터럴은 직렬화 라이브러리에 의해 생성되어야하는 클래스를 찾는 데 사용됩니다. 이렇게하면 각 클래스가 문자열 식별자와 함께 별도의 헤더 파일에있을 수 있습니다. 직렬화 될 수있는 파생 클래스의 별도 "사전 등록"을 유지할 필요가 없습니다. 이 등록 방법을 "키 내보내기"라고합니다.

도움이 될만한 정보가 있습니다. 자세한 내용은 다음을 참조하십시오. http://www.boost.org/doc/libs/1_54_0/libs/serialization/doc/index.html

+0

당신의 대답은 Thx지만 내 문제는 해결되지 않았습니다. ar.register_type은 BOOST_CLASS_EXPORT와 같습니다. 제 질문에서 언급했듯이 말입니다. 이것은 기본 클래스 포인터를 통해 직렬화 할 때 작동하지만 역 참조 된 기본 클래스 포인터를 통해 직렬화 할 때는 작동하지 않습니다. bus_route 예제에서 모든 파생 클래스는 기본 클래스 포인터 (bus_stop 포인터의 목록)에 직렬화됩니다. –

1

나는이 문제를 이해한다고 생각합니다. 당신이

ar >> *DerivedClass; 

을 할 때 당신은 operator<<참조를 전달된다. 이제 기본 클래스에 대한 참조를 통해 액세스 한 객체가 올바르게 직렬화되지 않았습니다. Boost-users 메일 링리스트에있는 Robert Ramey의 답변 this question에 대한 답변에서 모았습니다. 대답은 몇 년 전이지만, 생각해 보면 serialize 메서드가 가상이 아니라 (템플릿이기 때문에) 그들은 cannot be virtual이므로 여전히 사실이라고 생각합니다.

그래서 라이브러리는 포인터를 처리하기 위해 특별한 작업을 수행해야하지만 참조로 처리하지는 않습니다. 내가 찾은 못생긴 솔루션은 다음과 같이 (가상) 직렬화 함수의 쌍을 추가하는 것입니다 iarchiveoarchive이 원하는 아카이브로 대체해야

virtual myser(iarchive &ia) {ia >> *this;} 
virtual myser(oarchive &oa) {oa << *this;} 

.이것은 두 가지 추가 함수를 작성하는 것 외에 별도로 필요한 모든 아카이브 유형에 대해 명시 적으로 오버로드해야하기 때문에 정말 짜증납니다. 불행히도 나는 더 나은 해결책을 모른다.

+0

마지막으로 사용한 접근 방식은 ... 깨끗한 해결책이 없기 때문입니다. –