Boost Serialization调用错误的序列化方法

时间:2017-06-21 08:33:09

标签: c++ boost-serialization

我已使用macroBOOST_CLASS_EXPORT_KEY(T)用于标题文件,BOOST_CLASS_EXPORT_IMPLEMENT(T)用于实施文件,以便序列化<来自 base 类指针的strong> derived 类。

(**注意:我已将宏放在需要序列化的所有头文件和实现文件中,包括基类)

但是,在序列化到特定课程时遇到一个奇怪的问题。我遇到的问题是序列化在saving时是正确的,但在调用不同类序列化方法的loading时是错误的。

UPDATED:FYI,在从不同的类调用错误的序列化方法之后,抛出未注册的类的异常。该代码在binary_archive中只有问题,并且对text_archive工作正常,这对我来说很困惑,因为我认为如果text_archive序列化正常,那么binary_archive应该没有问题。或者我错过了一些需要在这里处理的非常明显的差异。

部分代码段如下:

仅供参考,尝试反序列化SubModelLayer时会出现问题。 SubModelLayer也会继承Node

template<typename Archive>
void ModelLayer::serialize(Archive & ar, const unsigned int version)
{
    // invoke serialization of the base class 
    ar & boost::serialization::base_object<Node>(*this);
    //this will actually call the 
    //ModelLayerData<_MODEL_LAYER_VERSION_ONE>::serialize
    //for serialization
    serialize_helper(_modelLayerData, ar, version);
}

template<typename Archive>
void ModelLayerData<_MODEL_LAYER_VERSION_ONE>::serialize(Archive & ar)
{
    ar & _xDimension;
    ar & _yDimension;
    ar & _zDimension;

    if (Archive::is_saving::value)
    {
        int dataType = static_cast<int>(_dataType);
        ar & dataType;
        size_t const totalSize = _xDimension*_yDimension*_zDimension;

        switch (_dataType)
        {
        case DataType::UCHAR:
            ar & boost::serialization::make_array<unsigned char>(_imageData.get(), totalSize);
            break;
        case DataType::USHORT:
            ar & boost::serialization::make_array<unsigned short>(_ushortImageData.get(), totalSize);
            break;
        default:
            std::string message = std::string(__FUNCTION__) + " | " + std::string(__FILE__);
            throw ModelLayerException::InvalidDataException(message);
            break;
        }

        size_t subModelLayerCollectionSize = _subModelLayerCollection.size();
        ar & subModelLayerCollectionSize;
        //submodellayer
        for (auto const &key : _subModelLayerCollection)
        {
            SubModelLayer *subModelLayer = key.second.get();
            ar & subModelLayer; //saving is calling the correct serialization method in SubModelLayer
        }
    }
    if (Archive::is_loading::value) //loading
    {
        int dataType;
        ar & dataType;
        _dataType = static_cast<DataType>(dataType);
        try
        {
            size_t const totalSize = _xDimension*_yDimension*_zDimension;
            switch (_dataType)
            {
            case DataType::UCHAR:
                _imageData.reset(new unsigned char[totalSize]);
                ar & boost::serialization::make_array<unsigned char>(_imageData.get(), totalSize);
                break;
            case DataType::USHORT:
                _ushortImageData.reset(new unsigned short[totalSize]);
                ar & boost::serialization::make_array<unsigned short>(_ushortImageData.get(), totalSize);
                break;
            default:
                std::string message = std::string(__FUNCTION__) + " | " + std::string(__FILE__);
                throw ModelLayerException::InvalidDataException(message);
                break;
            }
            int subModelLayerCollectionSize;
            ar & subModelLayerCollectionSize;
            for (size_t i = 0; i < subModelLayerCollectionSize; i++)
            {
                std::string timestamp;
                std::unique_ptr<SubModelLayer> subModelLayer;
                SubModelLayer * rawSubModelLayer = new SubModelLayer();
                //problem happens here
                ar & rawSubModelLayer; //loading is calling the wrong serialization method which is located in another class
                subModelLayer.reset(rawSubModelLayer);
                timestamp = subModelLayer->getTimestamp();
                _subModelLayerCollection.insert(std::map<std::string, std::unique_ptr<SubModelLayer>>::value_type(timestamp, std::move(subModelLayer)));
                switch (_dataType)
                {
                case DataType::UCHAR:
                    _subModelLayerCollection.at(timestamp)->setImageData(_imageData.get(), _xDimension, _yDimension, _zDimension);
                    break;
                case DataType::USHORT:
                    _subModelLayerCollection.at(timestamp)->setImageData(_ushortImageData.get(), _xDimension, _yDimension, _zDimension);
                    break;
                default:
                    std::string message = std::string(__FUNCTION__) + " | " + std::string(__FILE__);
                    throw ModelLayerException::InvalidDataException(message);
                    break;
                }
            }
        }
        catch (const std::exception& ex)
        {
            std::string message = std::string(ex.what()) + " " + std::string(__FUNCTION__) + " | " + std::string(__FILE__);
            throw ModelLayerException::AllocateImageDataException(message);
        }
    }
}

我怀疑由于滥用API而导致派生类注册时可能存在一些问题。

我的示例输出文件如下所示,我无法看到类的字符串标识符告诉boost要实例化和反序列化的类。

22 serialization::archive 13 0 1 1
0 0 1 5.714890957e+000 -1.402821732e+001 1.363411617e+001 5.255104303e-001 1.317463517e-001 -1.736424565e-001 8.223928213e-001 1.000000000e+000 1.410727501e+001 2.772170639e+001 2.090770340e+001 7.853981853e-001 1 0 2 1 1
1 1 0 3 1 1
2 10 10 10 0 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 4 4 1 1
3 10 10 10 0 0 0 10 10 10 0 4
4 10 10 10 0 0 0 10 10 10 0 4
5 10 10 10 0 0 0 10 10 10 0 4
6 10 10 10 0 0 0 10 10 10 0 0 -1.00000000000000000e+000 1.00000000000000000e+000

但是在coliru模仿我的类结构的一个小样本会生成包含类标识符的输出。

http://coliru.stacked-crooked.com/a/567d455fb020734d

UPDATE:附加了SubModelLayer标头和来源以及SubModelLayerData来源。

SubModelLayer.hpp

//SubModelLayer.hpp    
static const unsigned _SUB_MODEL_LAYER_DATA_VERSION = 1;
    static const unsigned _SUB_MODEL_LAYER_DATA_CURRENT_VERSION = _SUB_MODEL_LAYER_DATA_VERSION;

template<unsigned version>
class SubModelLayerData;

template<>
class SubModelLayerData<_SUB_MODEL_LAYER_DATA_VERSION> 
    : public Serializable, Setup
{
public:
    //No OIV object initialization should be done in constructor
    SubModelLayerData();
    ~SubModelLayerData();

    void setup();

    // Inherited via Serializable
    virtual void synchronize();

    template<typename Archive>
    void serialize(Archive & ar);

    int _xDimension;
    int _yDimension;
    int _zDimension;
    void *_data;
};

class SubModelLayer : public Node
{
public:
    SubModelLayer();
    ~SubModelLayer();
    // Inherited via Node
    virtual void synchronize() override;
    void setImageData(unsigned short * imageData, int const xDimension, int const yDimension, int const zDimension);
    void setImageData(unsigned char * imageData, int const xDimension, int const yDimension, int const zDimension);

private:
    friend class boost::serialization::access;
    template<typename Archive>
    void serialize(Archive & ar, const unsigned int version);

    // Inherited via Node
    virtual void setup() override;
    void renderSubModelLayer(int dataByteSize);

    //current version of sceneData
    SubModelLayerData<_SUB_MODEL_LAYER_DATA_CURRENT_VERSION> _subModelLayerData;
};

BOOST_CLASS_VERSION(SubModelLayer, _SUB_MODEL_LAYER_DATA_CURRENT_VERSION);
BOOST_CLASS_EXPORT_KEY(SubModelLayer);

SubModelLayer.cpp

//SubModelLayer.cpp
template void SubModelLayer::serialize(boost::archive::text_iarchive & ar, const unsigned int version);
template void SubModelLayer::serialize(boost::archive::text_oarchive & ar, const unsigned int version);
template void SubModelLayer::serialize(boost::archive::binary_iarchive & ar, const unsigned int version);
template void SubModelLayer::serialize(boost::archive::binary_oarchive & ar, const unsigned int version);


SubModelLayer::SubModelLayer()
    : Node(VArtObjectTypeID::SUBMODEL_LAYER)
{
    setup();
}

SubModelLayer::~SubModelLayer()
{
}

void SubModelLayer::setup()
{
    _subModelLayerData._root = getGroup();
    _subModelLayerData.setup();
    _subModelLayerData._root->setUserData(this);
}

template<typename Archive>
void SubModelLayer::serialize(Archive & ar, const unsigned int version)
{
    // invoke serialization of the base class
    ar & boost::serialization::base_object<Node>(*this);
    serialize_helper(_subModelLayerData, ar, version);
}

void SubModelLayer::synchronize()
{
    _subModelLayerData.synchronize();
}

void SubModelLayer::setImageData(unsigned short * imageData, int const xDimension, int const yDimension, int const zDimension)
{
    _subModelLayerData._data = imageData;
    _subModelLayerData._xDimension = xDimension;
    _subModelLayerData._yDimension = yDimension;
    _subModelLayerData._zDimension = zDimension;

    renderSubModelLayer(_UNSIGNED_SHORT_BYTE_SIZE);
}

void SubModelLayer::setImageData(unsigned char * imageData, int const xDimension, int const yDimension, int const zDimension)
{
    _subModelLayerData._data = imageData;
    _subModelLayerData._xDimension = xDimension;
    _subModelLayerData._yDimension = yDimension;
    _subModelLayerData._zDimension = zDimension;
    renderSubModelLayer(_UNSIGNED_CHAR_BYTE_SIZE);
}

BOOST_CLASS_EXPORT_IMPLEMENT(SubModelLayer);

SubModelLayerData.cpp

//SubModelLayerData.cpp
template void SubModelLayerData<_SUB_MODEL_LAYER_DATA_VERSION>::serialize(boost::archive::text_iarchive & ar);
template void SubModelLayerData<_SUB_MODEL_LAYER_DATA_VERSION>::serialize(boost::archive::text_oarchive & ar);
template void SubModelLayerData<_SUB_MODEL_LAYER_DATA_VERSION>::serialize(boost::archive::binary_iarchive & ar);
template void SubModelLayerData<_SUB_MODEL_LAYER_DATA_VERSION>::serialize(boost::archive::binary_oarchive & ar);

SubModelLayerData<_SUB_MODEL_LAYER_DATA_VERSION>::SubModelLayerData()
{
    _xDimension = 0;
    _yDimension = 0;
    _zDimension = 0;
}

template<typename Archive>
void SubModelLayerData<_SUB_MODEL_LAYER_DATA_VERSION>::serialize(Archive & ar)
{
    ar & _xDimension;
    ar & _yDimension;
    ar & _zDimension;
}

SubModelLayerData<_SUB_MODEL_LAYER_DATA_VERSION>::~SubModelLayerData()
{
}

void SubModelLayerData<_SUB_MODEL_LAYER_DATA_VERSION>::synchronize()
{
}

void SubModelLayerData<_SUB_MODEL_LAYER_DATA_VERSION>::setup()
{
}

更新:BTW,我使用下面的代码加载并保存二进制文件

Scene * scene;
{
    std::ifstream file(projectName, std::ios::binary);
    boost::archive::binary_iarchive ia{ file };
    ia >> scene;
}
return scene;

{
    std::ofstream ofs(projectName, std::ios::binary);
    boost::archive::binary_oarchive binaryArchive(ofs);
    binaryArchive << scene;
}

更新:调用堆栈显示在text_archive反序列化中调用binary_archive

enter image description here

我不理解的Boost序列化库的代码片段,问题发生在if(newbpis_ptr != bpis_ptr)之后的执行中。我是否违反了可能导致反序列化失败的任何事情。 最后,此方法之后抛出的异常是Unregistered Class

template<class Tptr>
static void invoke(Archive & ar, Tptr & t){
    check_load(*t);
    const basic_pointer_iserializer * bpis_ptr = register_type(ar, *t);
    const basic_pointer_iserializer * newbpis_ptr = ar.load_pointer(
        // note major hack here !!!
        // I tried every way to convert Tptr &t (where Tptr might
        // include const) to void * &.  This is the only way
        // I could make it work. RR
        (void * & )t,
        bpis_ptr,
        find
    );
    // if the pointer isn't that of the base class
    if(newbpis_ptr != bpis_ptr){
        t = pointer_tweak(newbpis_ptr->get_eti(), t, *t);
    }
}

0 个答案:

没有答案