开发者

boost::serialization: overloading load_construct_data: no accessible constructor at all

开发者 https://www.devze.com 2023-03-28 09:20 出处:网络
so I\'m using the boost::serialization library, and I\'m trying to overide how a class is constructed, since it has no default constructor. This 开发者_如何学JAVAis demonstrated here. To me it appears

so I'm using the boost::serialization library, and I'm trying to overide how a class is constructed, since it has no default constructor. This 开发者_如何学JAVAis demonstrated here. To me it appears the function takes the class* t and then sets it to point to a newly constructed object. If i'm wrong, this is definately the source of my error.

However, the only way to construct my class is by using another classes create() function, meaning I need to stray from the code in the example (this is stated in the boost::serialization namespace): ::new(t)my_class(attribute);

I tried simply calling the create function and setting t equal to the returned pointer, but this doesn't seem to work because right after the load_construct_data function, and in the serialization function, the given myClass& is not the same as what I set 't' to.

How do I do whatever ::new(t) is doing so the object created using the create function follows through into the serialize/other functions?


The construct referred to in your question (new(t) my_class(attribute)) is called "placement new". The way it work is that

  1. t must already point to an allocated region of memory (placement new doesn't do allocation by default)
  2. An instance of my_class is constructed at that memory location.

However, since in your case you can't use constructors, then using any form of new is out of the question. But there is an alternative (sort of).

Since placement new pretty much just overwrites a chunk memory, we can use a regular function which does the same with an already constructed object. Such a function is memcpy:

void * memcpy ( void * destination, const void * source, size_t num );

All memcpy does is perform a byte-wise copy of num bytes from the memory pointed to by source to the memory pointed to by destination.

So let's say you started with this code in the load_construct_data

my_class obj = other_class::create();

Then we can use the memcpy function to "move" the value at obj into the memory reference by t:

memcpy((void*)t, (void*)(&obj), sizeof(obj));

While there are some details about how this works with your particular class, such as whether a bit-wise copy is "good enough", this is the best I've got with what you've asked. The one problem I see is if the destructor releases resources, than the copy will may become invalid.

To account for the possible problems with destruction, you can write your own deep copying function:

void deepCopy( my_class * destination, const my_class * source );

which you call instead of memcpy.

Note: please tell me if I went astray with anything here. I don't currently have a machine to test code on.


In the case of not having a default constructor, the use of load_construct_data and save_construct data actually permits the use of shared_ptr instances. In my view, there is no need to play around with memcpy and raw pointers. Thus you can just do something like the following

#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/shared_ptr.hpp>
#include <boost/serialization/serialization.hpp>
#include <boost/serialization/string.hpp>

#include <memory>

class MyClass {
  public:
    explicit MyClass(std::string const &str) : m_str(str) {}
    MyClass() = delete;
    std::string str() const
    {
        return m_str;
    }
 private:
   std::string m_str;
};

namespace boost { namespace serialization {

    template<class Archive>
    void serialize(Archive &ar,
                   MyClass const & myClass,
                   unsigned int const) 
    {
        auto str = myClass.str();
        ar & str;
    }

    template<class Archive>
    void save_construct_data(Archive &ar,
                             MyClass const * myClass,
                             unsigned int const)
    {
        auto str = myClass->str();
        ar << str;
    }

    template<class Archive>
    void load_construct_data(Archive &ar,
                             MyClass * myClass,
                             unsigned int const)
    {
        std::string archived;
        ar >> archived;
        ::new(myClass)MyClass(MyClass(archived));
    }
}
}

int main(int argc, const char * argv[]) {

    std::shared_ptr<MyClass> myClass(new MyClass("hello!"));
    std::stringstream os;
    ::boost::archive::text_oarchive oa(os);
    oa << myClass;

    std::shared_ptr<MyClass> myClassB;
    std::stringstream is;
    is.str(os.str());
    ::boost::archive::text_iarchive ia(is);
    ia >> myClassB;

    return 0;
}
0

精彩评论

暂无评论...
验证码 换一张
取 消