Serialization of pointers with custom allocators

Hi! Is it possible to serialize a class A by pointer using a custom allocator? (Not the custom in-place allocator approach). I'm trying to serialize the (OpenCV) class IplImage. The class is used like this: IplImage* img = cvCreateImage(...); ... cvReleaseImage(&img); I've tried the following: template<class Archive> inline void load_construct_data(Archive & ar, IplImage * img, const unsigned int file_version){ ... IplImage* tmpImg = cvCreateImage(...); memcpy(img, tmpImg, sizeof(IplImage)); } But I get exceptions later, when releasing the loaded image. As far as I can tell, the image class data is identical before and after serialization, so I guess that the cvCreateImage/cvReleaseImage keep track of pointers somehow and things go bad when the ReleaseImage is called by a pointer not returned by the CreateImage function? Can the allocation of the IplImage used as input to load_construct_data be customized somehow? I also tried using an IplImage * & as input to load_construct_data: template<class Archive> inline void load_construct_data(Archive & ar, _IplImage * & img, const unsigned int file_version){ _IplImage* tmpImg = cvCreateImage(...); delete img; img = tmpImg; } But that screws up the (de)serialization. Any suggestions or thoughts anyone? // Anders Sundman

Try avoiding the default handling that serialization uses. template<class Archive> void save_image_ptr(Archive & ar, IplImage const * const iptr){ ar << binary_object(iptr, sizeof(IplImage)); } template<class Archive> void load_image_ptr(Archive & ar, IplImage * & iptr){ iptr = cvCreateImage(...); ar >> binary_object(iptr, sizeof(IplImage) } Robert Ramey Anders Sundman wrote:
Hi!
Is it possible to serialize a class A by pointer using a custom allocator? (Not the custom in-place allocator approach).
I'm trying to serialize the (OpenCV) class IplImage. The class is used like this:
IplImage* img = cvCreateImage(...); ... cvReleaseImage(&img);
I've tried the following:
template<class Archive> inline void load_construct_data(Archive & ar, IplImage * img, const unsigned int file_version){ ... IplImage* tmpImg = cvCreateImage(...); memcpy(img, tmpImg, sizeof(IplImage)); }
But I get exceptions later, when releasing the loaded image. As far as I can tell, the image class data is identical before and after serialization, so I guess that the cvCreateImage/cvReleaseImage keep track of pointers somehow and things go bad when the ReleaseImage is called by a pointer not returned by the CreateImage function?
Can the allocation of the IplImage used as input to load_construct_data be customized somehow?
I also tried using an IplImage * & as input to load_construct_data:
template<class Archive> inline void load_construct_data(Archive & ar, _IplImage * & img, const unsigned int file_version){ _IplImage* tmpImg = cvCreateImage(...); delete img; img = tmpImg; }
But that screws up the (de)serialization.
Any suggestions or thoughts anyone?
// Anders Sundman

Thank you for your prompt answer. Unfortunately, that doesn't seem to work. It doesn't matter that I pass a ref. to a pointer to the load_construct_data function. Since the library function: template<class Archive, class T> inline void load_construct_data_adl( Archive & ar, T * t, const unsigned int file_version ) in the serialization.hpp takes a pointer, and not a pointer ref. All changes to the pointer it self will be lost. And the pointer passed to the serialize function will not be the newly created one. Any other idéas that I could try? Perhaps it's time to bite the bullet and implement a custom in-place cvCreateImage function. Thank god that it's open source. Here is a real example that will not work: namespace boost { namespace serialization { template<class Archive> void serialize(Archive & ar, _IplImage& img, unsigned int version) { // <<<< The img input parameter here is the old img that was // originally allocated and passed to load_construct_data ar & img.roi; ar & make_binary_object(img.imageData, img.imageSize); } template<class Archive> inline void save_construct_data(Archive & ar, const _IplImage * const img, const unsigned int file_version){ ar << img->width; ar << img->height; ar << img->depth; ar << img->nChannels; } template<class Archive> inline void load_construct_data(Archive & ar, _IplImage * & img, const unsigned int file_version){ int w, h, d, c; ar >> w; ar >> h; ar >> d; ar >> c; img = cvCreateImage(cvSize(w, h), d, c); // <<< The new img I create here will never be passed to the serialize function } } } Robert Ramey skrev:
Try avoiding the default handling that serialization uses.
template<class Archive> void save_image_ptr(Archive & ar, IplImage const * const iptr){ ar << binary_object(iptr, sizeof(IplImage)); }
template<class Archive> void load_image_ptr(Archive & ar, IplImage * & iptr){ iptr = cvCreateImage(...); ar >> binary_object(iptr, sizeof(IplImage) }
Robert Ramey
Anders Sundman wrote:
Hi!
Is it possible to serialize a class A by pointer using a custom allocator? (Not the custom in-place allocator approach).
I'm trying to serialize the (OpenCV) class IplImage. The class is used like this:
IplImage* img = cvCreateImage(...); ... cvReleaseImage(&img);
I've tried the following:
template<class Archive> inline void load_construct_data(Archive & ar, IplImage * img, const unsigned int file_version){ ... IplImage* tmpImg = cvCreateImage(...); memcpy(img, tmpImg, sizeof(IplImage)); }
But I get exceptions later, when releasing the loaded image. As far as I can tell, the image class data is identical before and after serialization, so I guess that the cvCreateImage/cvReleaseImage keep track of pointers somehow and things go bad when the ReleaseImage is called by a pointer not returned by the CreateImage function?
Can the allocation of the IplImage used as input to load_construct_data be customized somehow?
I also tried using an IplImage * & as input to load_construct_data:
template<class Archive> inline void load_construct_data(Archive & ar, _IplImage * & img, const unsigned int file_version){ _IplImage* tmpImg = cvCreateImage(...); delete img; img = tmpImg; }
But that screws up the (de)serialization.
Any suggestions or thoughts anyone?
// Anders Sundman

try something like the following: #include <fstream> #include <boost/serialization/binary_object.hpp> #include <boost/serialization/split_member.hpp> #include <boost/archive/text_oarchive.hpp> #include <boost/archive/text_iarchive.hpp> class _IplImage { public: friend boost::serialization::access; int roi, width, height, depth, nChannels; int imageSize; int * imageData; template<class Archive> void save(Archive & ar, const unsigned int version) const { ar << roi << width << height << depth << nChannels; ar << imageSize; ar << boost::serialization::binary_object(imageData, imageSize); } template<class Archive> void load(Archive & ar, const unsigned int version){ ar >> roi >> width >> height >> depth >> nChannels; ar >> imageSize; ar >> boost::serialization::binary_object(imageData, imageSize); } BOOST_SERIALIZATION_SPLIT_MEMBER() }; main(int argc, char *argv[]){ const _IplImage i; { std::ofstream os("test"); boost::archive::text_oarchive oa(os); oa << i; } _IplImage new_i; { std::ifstream is("test"); boost::archive::text_iarchive ia(is); ia >> new_i; } // compare the new and old images } This compiles w/o issue on my system. Robert Ramey

Looking at this I might make one more small adjustment: Robert Ramey wrote:
try something like the following:
#include <fstream> #include <boost/serialization/binary_object.hpp> #include <boost/serialization/split_member.hpp> #include <boost/archive/text_oarchive.hpp> #include <boost/archive/text_iarchive.hpp>
class _IplImage { public: friend boost::serialization::access; int roi, width, height, depth, nChannels; int imageSize; int * imageData; template<class Archive> void save(Archive & ar, const unsigned int version) const { ar << roi << width << height << depth << nChannels; ar << imageSize; ar << boost::serialization::binary_object(imageData, imageSize); } template<class Archive> void load(Archive & ar, const unsigned int version){ ar >> roi >> width >> height >> depth >> nChannels; ar >> imageSize; imageData = CreateImageData(roi, width, height, depth, nChannels, imageSize); ar >> boost::serialization::binary_object(imageData, imageSize); } BOOST_SERIALIZATION_SPLIT_MEMBER() };
main(int argc, char *argv[]){ const _IplImage i; { std::ofstream os("test"); boost::archive::text_oarchive oa(os); oa << i; } _IplImage new_i; { std::ifstream is("test"); boost::archive::text_iarchive ia(is); ia >> new_i; } // compare the new and old images }
This compiles w/o issue on my system.
Robert Ramey

Thank you for the tip and for all the time you have spent helping me. I really appreciate it. Since we use the IplImage from a 3:rd party library I would like to try every possible work-around before forking of the library source (and having to maintain it) by adding member functions. But in the end, I might be forced to do just that. In that case I'll try your solution bellow. For now, I'll keep working to find some workaround using free functions. Best Regards, Anders Sundman Robert Ramey skrev:
Looking at this I might make one more small adjustment:
Robert Ramey wrote:
try something like the following:
#include <fstream> #include <boost/serialization/binary_object.hpp> #include <boost/serialization/split_member.hpp> #include <boost/archive/text_oarchive.hpp> #include <boost/archive/text_iarchive.hpp>
class _IplImage { public: friend boost::serialization::access; int roi, width, height, depth, nChannels; int imageSize; int * imageData; template<class Archive> void save(Archive & ar, const unsigned int version) const { ar << roi << width << height << depth << nChannels; ar << imageSize; ar << boost::serialization::binary_object(imageData, imageSize); } template<class Archive> void load(Archive & ar, const unsigned int version){ ar >> roi >> width >> height >> depth >> nChannels; ar >> imageSize; imageData = CreateImageData(roi, width, height, depth, nChannels, imageSize); ar >> boost::serialization::binary_object(imageData, imageSize); } BOOST_SERIALIZATION_SPLIT_MEMBER() };
main(int argc, char *argv[]){ const _IplImage i; { std::ofstream os("test"); boost::archive::text_oarchive oa(os); oa << i; } _IplImage new_i; { std::ifstream is("test"); boost::archive::text_iarchive ia(is); ia >> new_i; } // compare the new and old images }
This compiles w/o issue on my system.
Robert Ramey
participants (2)
-
Anders Sundman
-
Robert Ramey