0

我正在阅读其他人的代码,并且有此类的序列化版本:

struct ObjectInfo
{
    int32_t m_typeId;
    string m_objectName;
    vector<int32_t> m_haveKeysId; 
    map<int32_t,double> m_objectFeatures;
    
    ObjectInfo():m_typeId(-1),m_objectName("")
    {
        m_objectFeatures.clear();
        m_haveKeysId.clear();
    }
}

它的二进制版本如下:

struct ObjectInfo_B
{
    int32_t m_typeId;
    int32_t m_objectNamePos;
    
    int32_t m_startIndex;
    int32_t m_endIndex;

    int32_t m_haveKeysIdStartIndex;
    int32_t m_haveKeysIdEndIndex;
    
    ObjectInfo_B()
    {
        m_typeId = -1;
        m_objectNamePos = 0;
        m_startIndex = -1;
        m_endIndex = -1;
        m_haveKeysIdStartIndex = -1;
        m_haveKeysIdEndIndex = -1;
    }

然后有一个ObjectInfo的向量:

vector<ObjectInfo> *objectsVec;
ObjectInfo_B *bObjects;

...

现在要转换的代码如下:

startIndex = 0;
int32_t curBufferSize = 0;
for(size_t i = 0;i<objectsVec->size();i++)
{
    bObjects[i].m_typeId = (*objectsVec)[i].m_typeId;
    bObjects[i].m_objectNamePos = curBufferSize;
    
    strcpy(m_objectNameBuffer+curBufferSize,(*objectsVec)[i].m_objectName.c_str());
    curBufferSize += (*objectsVec)[i].m_objectName.size() + 1;
    
    bObjects[i].m_startIndex = startIndex;
    bObjects[i].m_endIndex = startIndex + (*objectsVec)[i].m_objectFeatures.size();
    startIndex = bObjects[i].m_endIndex;

    bObjects[i].m_haveKeysIdStartIndex = haveKeyStartIndex;
    bObjects[i].m_haveKeysIdEndIndex = haveKeyStartIndex +(*objectsVec)[i].m_haveKeysId.size();

...

fwrite((char*)bObjects,sizeof(ObjectInfo_B),wcount,output);

这似乎很复杂,我不是连载的农家乐。有没有更简单的方法在 C++ 中做到这一点?快速搜索表明,下面的这个可以做类似的事情,但是它可以用更简单的方式对上面的代码进行转换吗?

https://www.boost.org/doc/libs/1_37_0/libs/serialization/doc/index.html
4

2 回答 2

0

The main question is why you want to hold two different versions of the same class. If the main purpose of the binary version is providing a binary I/O, I'd recommend writing a corresponding I/O function. Here's a simple example.

If you are dealing with legacy code, a constructor of ObjectInfo_b from ObjectInfo makes the code more readable:

ObjectInfo_b(const ObjectInfo& obj) {
    // copy all member variables according to your code snippet
    m_typeId = obj.m_typeId;
    // ...
}

Then the serialization part looks like this

vector<ObjectInfo> objectsVec;  // Note: removed pointer
vector<ObjectInfo_b> bObjects; // also using a std::vector

for (const ObjectInfo obj : objectsVec) {
    // create ObjectInfo_b from obj and append to vector via move semantics
    bObjects.emplace_back(ObjectInfo_b(obj)); 
}
// ...
// Pointer to objects
bObjects* bObject_ptr = &bObjects[0];

Again, with the provided information, the class seems duplicate and should be removed. A function that writes ObjectInfo in a binary format is sufficient.

于 2021-12-09T04:40:42.013 回答
0

我将重构代码的方向草图:

#include <cstdint>
#include <iostream>
#include <fstream>
#include <bitcast>

struct B
{
};

struct ObjectInfo_B
{
    std::int32_t m_typeId = -1;
    std::int32_t m_objectNamePos = -1;
    
    std::int32_t m_startIndex = -1;
    std::int32_t m_endIndex = -1;

    std::int32_t m_haveKeysIdStartIndex = -1;
    std::int32_t m_haveKeysIdEndIndex = -1;

};

auto get_data_from_objects(const std::vector<B>& objects)
{
    std::int32_t startIndex{0};
    std::int32_t curBufferSize{0};
    std::vector<ObjectInfo_B> object_infos(objects.size());
    
    for (std::size_t n = 0; n < object.size(); n++ )
    {
        auto& object_info = objects_info[n];
        auto& object = objects[n];
        
        object_info.m_typeId = object.m_typeId;
        object_info.m_objectNamePos = curBufferSize;
        ....
    }
    
}


std::ostream operator<<(std::ostream& os, const std::vector<ObjectInfo_B>& object_infos)
{
    for(const ObjectInfo_B& object_info : object_infos)
    {
        os.fwrite(std::bitcast<char*>(&object_info), sizeof(ObjectInfo_B));
    }
}


void save_to(std::ostream& os, const std::vector<B>& objects)
{
   auto object_infos = get_data_from_objects(objects);
   os << object_infos();
}
于 2021-12-09T06:03:55.747 回答