BOOST_CLASS_EXPORT_ *宏无法像register_type()一样工作 [英] BOOST_CLASS_EXPORT_* macros are not working like register_type()

查看:94
本文介绍了BOOST_CLASS_EXPORT_ *宏无法像register_type()一样工作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当我将派生对象序列化到文件中,并在使用boost导出宏时从该文件序列化到基类指针时,出现unregistered_class异常.当我用存档的register_type()方法替换宏时,它可以工作.我需要使用宏,因为应用程序的大小和复杂性使register_type()方法不切实际.

I am getting an unregistered_class exception when I serialize out a derived object to a file and serialize in from that file to a base class pointer when I use the boost export macros. When I replace the macros with the archive register_type() methods, it works. I need to use the macros because the application size and complexity makes the register_type() methods impractical.

我正在使用RHEL 7.4,boost 1.53和C ++ 11.这些类在共享库中.这里是示例代码来演示此问题.照原样,它引发异常.如果我注释掉宏并取消注释功能,它将起作用.testera.h

I am using RHEL 7.4, boost 1.53, and C++11. The classes are in shared libraries. Here is sample code to demonstrate the problem. As is, it throws the exception. If I comment out the macros and uncomment the functions, it works. 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

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

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

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

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

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

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 $@

推荐答案

从文档中:包含任何存档类标题的同一源模块中的

BOOST_CLASS_EXPORT 将实例化将指定类型的多态指针序列化为所有那些存档类所需的代码.如果不包括存档类标题,则不会实例化任何代码.

BOOST_CLASS_EXPORT in the same source module that includes any of the archive class headers will instantiate code required to serialize polymorphic pointers of the indicated type to the all those archive classes. If no archive class headers are included, then no code will be instantiated.

在这种情况下,棘手的细节是您确实包含了/some/存档头,但是/not/实际上是在进行序列化的具体类型.

In this case the tricky detail is that you did include /some/ archive headers, but /not/ the concrete type that's actually doing the serialization.

另一个棘手的细节可能与以下问题有关:当您拆分_KEY/_IMPLEMENT部分并且仅在_IMPLEMENT部分之前包含了归档头时,它是否仍然有效.我想您可以轻松地对此进行测试.

Another tricky detail might be related to the question whether it still works when you have split the _KEY/_IMPLEMENT parts and you have the archive headers included before the _IMPLEMENT parts only. I suppose you could easily test this.

序列化/反序列化不平衡.如果您反序列化 A * ,则必须也要序列化该类型之一.

The serialization/deserialization is not in balance. If you deserialize a A*, you MUST also serialize one of that type.

此外,您可以简化并组合makefile,并且可能不需要在标头中包含那么多的序列化.

Also, you can simplify and combine the makefile, and probably don't need quite as many serialization include in your headers.

在本地工作.只需 make&&./tester_mn:

  1. testera.h

  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)

  • testerb.h

  • 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)
    

  • testera.cpp

  • 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; }
    

  • testerb.cpp

  • 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;
    }
    

  • test.cpp

  • 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;
    }
    

  • Makefile

  • 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)
    

  • 这篇关于BOOST_CLASS_EXPORT_ *宏无法像register_type()一样工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆