BOOST_CLASS_EXPORT_ * макросы не работают как register_type () - PullRequest
0 голосов
/ 28 сентября 2018

Я получаю исключение unregistered_class при сериализации производного объекта в файл и сериализации из этого файла в указатель базового класса, когда я использую макросы экспорта экспорта.Когда я заменяю макросы методами архива register_type (), это работает.Мне нужно использовать макросы, потому что размер и сложность приложения делают методы register_type () непрактичными.

Я использую RHEL 7.4, boost 1.53 и C ++ 11.Занятия в общих библиотеках.Вот пример кода, чтобы продемонстрировать проблему.Как есть, это исключение.Если я закомментирую макросы и раскомментирую функции, это работает.testera.h

#ifndef testera_h
#define testera_h

#include <boost/serialization/serialization.hpp>
#include <boost/archive/polymorphic_oarchive.hpp>
#include <boost/archive/polymorphic_iarchive.hpp>
#include <boost/serialization/export.hpp>
#include <boost/serialization/string.hpp>

class A
{
private:
    friend class boost::serialization::access;

    template< class Arch >
    void
    serialize( Arch &ar, const unsigned int ver );

public:
    A(); 

    virtual ~A() {}

    void setStr( const std::string &s );
    std::string getStr();

protected:
    std::string myStr;
};

BOOST_CLASS_EXPORT_KEY(A)

#endif

testera.C

#include "testera.h"

BOOST_CLASS_EXPORT_IMPLEMENT(A)


template
void
A::serialize<boost::archive::polymorphic_oarchive>(  boost:archive::polymorphic_oarchive &ar, const unsigned int ver );

template
void
A::serialize<boost::archive::polymorphic_iarchive>( boost::archive::polymorphic_iarchive &ar, const unsigned int ver );

A::A() : myStr( "a" ) 
{
}

void
A::setStr( const std::string &s )
{
    myStr = s;
}

std::string
A::getStr()
{
    return myStr;
}


template<class Arch>
void
A::serialize( Arch &ar, const unsigned int ver )
{
    ar & myStr;
}

testerb.h

#ifndef testerb_h
#define testerb_h

#include "testera.h"

class B : public A
{
private:
    friend class boost::serialization::access;

    template< class Arch >
    void
    serialize( Arch &ar, const unsigned int ver );

public:
    B();

    virtual ~B() {}

    void set( const int i );
    int get();

protected:
    int myI;
};

BOOST_CLASS_EXPORT_KEY(B)
#endif

testerb.C

#include "testerb.h"

BOOST_CLASS_EXPORT_IMPLEMENT(B)

template
void 
B::serialize<boost::archive::polymorphic_oarchive>( boost::archive::polymorphic_oarchive &ar, const unsigned int ver );

template
void
B::serialize<boost::archive::polymorphic_iarchive>( boost::archive::polymorphic_iarchive &ar, const unsigned int ver );
B::B(): myI( 1 )
{ 
    myStr = "b"; 
}

void 
B::set( const int i ) 
{
    myI = i;
}

int 
B::get() 
{
    return myI;
}

template< class Arch >
void
B::serialize( Arch &ar, const unsigned int ver )
{
    // boost::serialization::void_cast_register< B, A >( static_cast< B *>( NULL ), static_cast< A * >( NULL ) );
    ar & boost::serialization::base_object<A>( *this );

    ar & myI;
}

tester_mn.C

#include "testerb.h"
#include <boost/archive/polymorphic_text_oarchive.hpp>
#include <boost/archive/polymorphic_text_iarchive.hpp>
#include <fstream>

int main( int argc, char *argv[] )
{
    int ret = 0;
    B obj;
    obj.set( 2 );

    A *ptr = NULL;

    if( argc > 1 )
    {
        try
        {
            std::string fl = argv[ 1 ];
            {
                std::ofstream ofl( fl.c_str() );

                /*
                oar->register_type(static_cast<A *>(NULL));
                oar->register_type(static_cast<B *>(NULL));
                */
                try
                {
                    boost::archive::polymorphic_text_oarchive toar( ofl );
                    toar & obj;
                }
                catch( std::exception &e )
                {
                    std::cerr << "Error: archive from B to file " << fl << " - " << e.what() << std::endl;
                    ret = 1;
                }
            }

            if( ! ret )
            {
                ptr = NULL;

                {
                    std::ifstream ifl( fl.c_str() );
                    /*
                    iar->register_type(static_cast<A *>(NULL));
                    iar->register_type(static_cast<B *>(NULL));
                    */

                    try
                    {
                        boost::archive::polymorphic_text_iarchive tiar( ifl );

                        tiar & ptr;
                    }
                    catch( std::exception &e )
                    {
                        std::cerr << "Error: archive from file " << fl << " to B * - " << e.what() << std::endl;
                        ret = 1;
                    }
                    catch( ... )
                    {
                        std::cerr << "Error: Caught excpeption" << std::endl;
                        ret = 1;
                    }
                }


                if( ! ret )
                {
                    std::cout << static_cast<B*>(ptr)->get() << std::endl;
                }
            }
        }
        catch( ... )
        {
            std::cerr << "Caught exception" << std::endl;
            ret = 1;
        }

    }


    return ret;
}

Makefile_lib

CXXFLAGS = -c -ggdb3  -fPIC -funswitch-loops -fgcse-after-reload -std=c++11 
LDFLAGS = -std=c++11 -lboost_serialization -lboost_thread -lboost_system -lboost_filesystem

OBJLOC = obj

OBJS = $(OBJLOC)/testera.o \
    $(OBJLOC)/testerb.o

LIBRARY_NAME = libtester.so

libs:$(LIBRARY_NAME)

$(LIBRARY_NAME): $(OBJS)
    ${CXX} -shared -o $@ $(OBJS)

$(OBJLOC)/%.o: ./%.C
    $(CXX) $(CXXFLAGS) ./$*.C -o $(OBJLOC)/$*.o

Makefile_mn

CXXFLAGS = -ggdb3  -funswitch-loops -fgcse-after-reload -std=c++11 
LDFLAGS = -lboost_serialization -lboost_thread -lboost_system -lboost_filesystem -L. -ltester


tester_mn: tester_mn.o
    ${CXX} $(CXXFLAGS) $(LDFLAGS) tester_mn.C  -o $@

1 Ответ

0 голосов
/ 28 сентября 2018

Из документов: Экспорт сериализации класса

BOOST_CLASS_EXPORT в том же исходном модуле, который содержит любой из заголовков архивных классов, будет создавать код, необходимый длясериализовать полиморфные указатели указанного типа на все эти архивные классы. Если заголовки класса архива не включены, то экземпляр кода не будет создан.

В этом случае сложная деталь заключается в том, что вы включили / некоторые / заголовки архива, но / нет/ конкретный тип, который на самом деле выполняет сериализацию.

Еще одна хитрая деталь может быть связана с вопросом, работает ли он по-прежнему, когда вы разбили части _KEY / _IMPLEMENT и у вас есть архивные заголовки, включенные перед только частями _IMPLEMENT,Я полагаю, вы могли бы легко это проверить.

Другие проблемы

Сериализация / десериализация не сбалансирована.Если вы десериализовали A*, вы ДОЛЖНЫ также сериализовать один из этого типа.

Кроме того, вы можете упростить и объединить make-файл, и, вероятно, вам не нужно так много сериализации, включаяв ваших заголовках.

Здесь Полный код

Как работает локально.Просто make && ./tester_mn:

  1. testera.h

    #pragma once
    
    #include <boost/serialization/export.hpp>
    #include <boost/serialization/serialization.hpp>
    
    class A {
      private:
        friend class boost::serialization::access;
    
        template <class Arch> void serialize(Arch &ar, const unsigned int ver);
    
      public:
        A();
    
        virtual ~A() {}
    
        void setStr(const std::string &s);
        std::string getStr();
    
      protected:
        std::string myStr;
    };
    
    BOOST_CLASS_EXPORT_KEY(A)
    
  2. testerb.h

    #pragma once
    #include "testera.h"
    
    class B : public A {
      private:
        friend class boost::serialization::access;
        template <class Arch> void serialize(Arch &, unsigned);
    
      public:
        B();
    
        virtual ~B() {}
        void set(int i);
        int get();
    
      protected:
        int myI;
    };
    
    BOOST_CLASS_EXPORT_KEY(B)
    
  3. testera.cpp

    #include "testera.h"
    #include <boost/archive/polymorphic_iarchive.hpp>
    #include <boost/archive/polymorphic_oarchive.hpp>
    #include <boost/serialization/string.hpp>
    
    BOOST_CLASS_EXPORT_IMPLEMENT(A)
    
    template void A::serialize<boost::archive::polymorphic_oarchive>(boost::archive::polymorphic_oarchive &, unsigned);
    template void A::serialize<boost::archive::polymorphic_iarchive>(boost::archive::polymorphic_iarchive &, unsigned);
    
    A::A() : myStr("a")                  {               } 
    void A::setStr(const std::string &s) { myStr = s;    } 
    std::string A::getStr()              { return myStr; } 
    
    template <class Arch> void A::serialize(Arch &ar, unsigned) { ar &myStr; }
    
  4. testerb.cpp

    #include "testerb.h"
    #include <boost/archive/polymorphic_iarchive.hpp>
    #include <boost/archive/polymorphic_oarchive.hpp>
    
    BOOST_CLASS_EXPORT_IMPLEMENT(B)
    
    template void B::serialize<boost::archive::polymorphic_oarchive>(boost::archive::polymorphic_oarchive &, unsigned);
    template void B::serialize<boost::archive::polymorphic_iarchive>(boost::archive::polymorphic_iarchive &, unsigned);
    
    B::B() : myI(1)          { myStr = "b"; } 
    void B::set(const int i) { myI = i;     } 
    int B::get()             { return myI;  } 
    
    template <class Arch> void B::serialize(Arch &ar, unsigned) {
        ar &boost::serialization::base_object<A>(*this);
        ar &myI;
    }
    
  5. test.cpp

    #include "testerb.h"
    #include <boost/archive/polymorphic_text_iarchive.hpp>
    #include <boost/archive/polymorphic_text_oarchive.hpp>
    #include <fstream>
    
    int main() try {
    
        std::string const fl = "test.data";
        {
            std::ofstream ofl(fl.c_str());
    
            boost::archive::polymorphic_text_oarchive toar(ofl);
            B obj;
            obj.set(42);
    
            {
                A *ptr = &obj;
                toar &ptr;
            }
        }
    
        {
            A *ptr = nullptr;
            std::ifstream ifl(fl.c_str());
    
            boost::archive::polymorphic_text_iarchive tiar(ifl);
    
            tiar &ptr;
    
            if (B *b = dynamic_cast<B *>(ptr)) {
                std::cout << b->get() << std::endl;
            }
        }
    } catch (std::exception &e) {
        std::cerr << "Error: " << e.what() << std::endl;
        return 1;
    } catch (...) {
        std::cerr << "Error: Caught excpeption" << std::endl;
        return 1;
    }
    
  6. Makefile

    all: libs tester_mn
    
    CXXFLAGS += -I ~/custom/boost
    LDFLAGS  += -L ~/custom/boost/stage/lib
    CXXFLAGS += -ggdb3  -fPIC -funswitch-loops -fgcse-after-reload -std=c++11 
    LDFLAGS  += -lboost_serialization -lboost_thread -lboost_system -lboost_filesystem
    
    OBJLOC = obj
    OBJS += $(OBJLOC)/testera.o
    OBJS += $(OBJLOC)/testerb.o
    
    LIBRARY_NAME = libtester.so
    
    libs:$(LIBRARY_NAME)
    
    $(LIBRARY_NAME): $(OBJS)
        ${CXX} -shared -o $@ $(OBJS)
    
    $(OBJLOC)/%.o: ./%.cpp
        mkdir -pv $(@D)
        $(CXX) -c $(CXXFLAGS) $< -o $@
    
    tester_mn: LDFLAGS += -L. -ltester
    tester_mn: test.o $(OBJS) | libs
        ${CXX} $(CXXFLAGS) $^ -o $@ $(LDFLAGS)
    
...