2013-03-25 8 views
15

में क्लास ट्रैकिंग के बिना व्युत्पन्न क्लास क्रमबद्धता बेस बेस पॉइंटर के माध्यम से व्युत्पन्न कक्षा को क्रमबद्ध करते समय मुझे बूस्ट क्रमबद्धता के साथ कुछ समस्याएं हैं। मुझे एक ऐसी प्रणाली की आवश्यकता है जो सिस्टम में प्राप्त होने वाली कुछ वस्तुओं को क्रमबद्ध करे, इसलिए मुझे समय के साथ क्रमबद्ध करने की आवश्यकता है। यह वास्तव में एक समस्या नहीं है क्योंकि मैं boost::archive::binary_oarchive खोल सकता हूं और आवश्यकता होने पर वस्तुओं को क्रमबद्ध कर सकता हूं। तेजी से मैंने देखा कि बूस्ट मेमोरी एड्रेस द्वारा ऑब्जेक्ट ट्रैकिंग कर रहा था, इसलिए पहली समस्या यह थी कि उसी ऑब्जेक्ट को साझा करने वाले समय में अलग-अलग ऑब्जेक्ट्स को उसी ऑब्जेक्ट के रूप में सहेजा गया था। यह आवश्यक व्युत्पन्न वर्ग में निम्नलिखित मैक्रो का उपयोग द्वारा निर्धारित किया जा सकता है:बूस्ट (सी ++)

BOOST_CLASS_TRACKING(className, boost::serialization::track_never)

यह ठीक है, लेकिन फिर, जब आधार वर्ग सार नहीं है, आधार वर्ग ठीक से धारावाहिक नहीं है काम करता है। निम्नलिखित उदाहरण में, बेस क्लास क्रमबद्धता विधि को केवल पहली वस्तु के साथ बुलाया जाता है। निम्नलिखित में, बढ़ावा देता है कि इस ऑब्जेक्ट को पहले से क्रमबद्ध किया गया है हालांकि ऑब्जेक्ट के अलग-अलग प्रकार हैं।

#include <iostream> 
#include <fstream> 
#include <boost/serialization/export.hpp> 
#include <boost/serialization/base_object.hpp> 
#include <boost/serialization/list.hpp> 
#include <boost/serialization/map.hpp> 
#include <boost/serialization/vector.hpp> 
#include <boost/serialization/shared_ptr.hpp> 
#include <boost/archive/archive_exception.hpp> 
#include <boost/archive/binary_oarchive.hpp> 
#include <boost/archive/binary_iarchive.hpp> 

using namespace std; 

class AClass{ 
public: 
    AClass(){} 
    virtual ~AClass(){} 
private: 
    double a; 
    double b; 
    //virtual void virtualMethod() = 0; 
private: 
    friend class boost::serialization::access; 
    template<class Archive> 
    void serialize(Archive & ar, const unsigned int version) 
    { 
     ar & a; 
     ar & b; 
     cout << "A" << endl; 
    } 
}; 
//BOOST_SERIALIZATION_ASSUME_ABSTRACT(Aclass) 
//BOOST_CLASS_TRACKING(AClass, boost::serialization::track_never) 

class BClass : public AClass{ 
public: 
    BClass(){} 
    virtual ~BClass(){} 
private: 
    double c; 
    double d; 
    virtual void virtualMethod(){}; 
private: 
    friend class boost::serialization::access; 
    template<class Archive> 
    void serialize(Archive & ar, const unsigned int version) 
    { 
     ar & boost::serialization::base_object<AClass>(*this); 
     ar & c; 
     ar & d; 
     cout << "B" << endl; 
    } 
}; 
// define export to be able to serialize through base class pointer 
BOOST_CLASS_EXPORT(BClass) 
BOOST_CLASS_TRACKING(BClass, boost::serialization::track_never) 


class CClass : public AClass{ 
public: 
    CClass(){} 
    virtual ~CClass(){} 
private: 
    double c; 
    double d; 
    virtual void virtualMethod(){}; 
private: 
    friend class boost::serialization::access; 
    template<class Archive> 
    void serialize(Archive & ar, const unsigned int version) 
    { 
     ar & boost::serialization::base_object<AClass>(*this); 
     ar & c; 
     ar & d; 
     cout << "C" << endl; 
    } 
}; 
// define export to be able to serialize through base class pointer 
BOOST_CLASS_EXPORT(CClass) 
BOOST_CLASS_TRACKING(CClass, boost::serialization::track_never) 

int main() { 
    cout << "Serializing...." << endl; 
    { 
     ofstream ofs("serialization.dat"); 
     boost::archive::binary_oarchive oa(ofs); 
     for(int i=0;i<5;i++) 
     { 
      AClass* baseClassPointer = new BClass(); 
      // serialize object through base pointer 
      oa << baseClassPointer; 
      // free the pointer so next allocation can reuse memory address 
      delete baseClassPointer; 
     } 

     for(int i=0;i<5;i++) 
     { 
      AClass* baseClassPointer = new CClass(); 
      // serialize object through base pointer 
      oa << baseClassPointer; 
      // free the pointer so next allocation can reuse memory address 
      delete baseClassPointer; 
     } 
    } 
    getchar(); 
    cout << "Deserializing..." << endl; 
    { 
     ifstream ifs("serialization.dat"); 
     boost::archive::binary_iarchive ia(ifs); 
     try{ 
      while(true){ 
       AClass* a; 
       ia >> a; 
       delete a; 
      } 
     }catch(boost::archive::archive_exception const& e) 
     { 

     } 
    } 
    return 0; 
} 

जब कोड के इस टुकड़े को क्रियान्वित करने, परिणाम के रूप में अनुवर्ती है:

Serializing.... 
A 
B 
B 
B 
B 
B 
C 
C 
C 
C 
C 

Deserializing... 
A 
B 
B 
B 
B 
B 
C 
C 
C 
C 
C 

तो आधार वर्ग केवल एक बार हालांकि व्युत्पन्न वर्ग स्पष्ट रूप track_never झंडा है धारावाहिक की जा रही है। इस व्यवहार को ठीक करने के लिए दो अलग-अलग कामकाज हैं। सबसे पहला बेस वर्चुअल वर्चुअल विधि के साथ मूल वर्ग सार बनाना और मैक्रो BOOST_SERIALIZATION_ASSUME_ABSTRACT(Aclass) को कॉल करना है, और दूसरा एक बेस क्लास (कोड में टिप्पणी) में track_never ध्वज भी डालना है।

इनमें से कोई भी समाधान मेरी आवश्यकताओं को पूरा नहीं करता है, क्योंकि मैं सिस्टम राज्य के भविष्य के समयबद्ध क्रमिकरणों में करना चाहता हूं, जिसके लिए दिए गए डीसीएलएएस के लिए ट्रैकिंग सुविधाओं की आवश्यकता होगी (बी या सी नहीं), और एसीलास भी चाहिए अमूर्त नहीं है।

कोई संकेत? आधार वर्ग में ट्रैकिंग सुविधा से बचने के लिए स्पष्ट रूप से बेस क्लास क्रमबद्धता विधि को कॉल करने का कोई तरीका है (जिसे पहले ही व्युत्पन्न वर्ग में अक्षम कर दिया गया है)?

+0

बढ़ावा दे सकता है ए को वर्चुअल होने के बावजूद वर्चुअल होने के लिए (मेरा मतलब है, बस 'BOOST_SERIALIZATION_ASSUME_ABSTRACT (एक्लास)' लाइन को असम्बद्ध करें और संकलित करने का प्रयास करें)? – Synxis

उत्तर

2

बढ़ावा देने के लिए थोड़ा करीब देखने के बाद :: serialization मुझे भी आश्वस्त है कि आपके अनुरोध के लिए कोई सीधा समाधान नहीं है। जैसा कि आपने पहले ही उल्लेख किया है कि सीरियलाइजेशन के लिए ट्रैकिंग व्यवहार को कक्षा बेस द्वारा BOOST_CLASS_TRACKING के साथ घोषित किया गया है। यह कॉन्स वैश्विक जानकारी कक्षा oserializer से ट्रैकिंग वर्चुअल विधि में व्याख्या की तुलना में है।

virtual bool tracking(const unsigned int /* flags */) 

क्योंकि यह एक टेम्पलेट वर्ग है क्योंकि आप स्पष्ट रूप से अपनी कक्षाओं के लिए इस विधि को तुरंत चालू कर सकते हैं।

namespace boost { 
namespace archive { 
namespace detail { 

template<> 
    virtual bool oserializer<class binary_oarchive, class AClass >::tracking(const unsigned int f /* flags */) const { 
     return do_your_own_tracking_decision(); 
    } 

}}} 

अब आप वैश्विक चर की तरह कुछ करने की कोशिश कर सकते हैं और समय-समय पर ट्रैकिंग व्यवहार को बदल सकते हैं। (उदा। संग्रह के लिए कौन सी व्युत्पन्न कक्षा लिखी गई है।) ऐसा लगता है कि "सीरियलाइजिंग" के लिए wok लेकिन अपवाद फेंकने से "Deserializing" लगता है। इसका कारण यह है कि प्रत्येक वर्ग के लिए "ट्रैकिंग" की स्थिति केवल संग्रह में लिखी जाती है। इसलिए deserialize हमेशा AClass के लिए डेटा की अपेक्षा करता है अगर बीसीएलएएस या सीसीएलएएस पढ़ा जाता है (लीज्ड पर अगर AClass के लिए पहला लिखने का प्रयास अक्षम अक्षम था)।

ट्रैकिंग() विधि में झंडे पैरामीटर का उपयोग करने के लिए एक संभावित समाधान हो सकता है। यह पैरामीटर संग्रह के साथ बनाए गए झंडे का प्रतिनिधित्व करता है, डिफ़ॉल्ट "0"।

binary_oarchive(std::ostream & os, unsigned int flags = 0) 

संग्रह झंडे basic_archive.hpp घोषित किये गए हैं

enum archive_flags { 
    no_header = 1, // suppress archive header info 
    no_codecvt = 2, // suppress alteration of codecvt facet 
    no_xml_tag_checking = 4, // suppress checking of xml tags 
    no_tracking = 8,   // suppress ALL tracking 
    flags_last = 8 
}; 

no_tracking वर्तमान में समर्थित होने की नहीं लगती है, लेकिन अब आप पर नज़र रखने के लिए इस व्यवहार जोड़ सकते हैं।

template<> 
    virtual bool oserializer<class binary_oarchive, class AClass >::tracking(const unsigned int f /* flags */) const { 
     return !(f & no_tracking); 
    } 

अब आप पर पट्टे पर कर सकते हैं विभिन्न अभिलेखागार के लिए तय Aclass या नज़र रखी जानी चाहिए नहीं।

boost::archive::binary_oarchive oa_nt(ofs, boost::archive::archive_flags::no_tracking); 

और यह आपके उदाहरण में बदलाव हैं।

int main() { 
    cout << "Serializing...." << endl; 
    { 
     ofstream ofs("serialization1.dat"); 
     boost::archive::binary_oarchive oa_nt(ofs, boost::archive::archive_flags::no_tracking); 
     //boost::archive::binary_oarchive oa(ofs); 
     for(int i=0;i<5;i++) 
     { 
      AClass* baseClassPointer = new BClass(); 
      // serialize object through base pointer 
      oa_nt << baseClassPointer; 
      // free the pointer so next allocation can reuse memory address 
      delete baseClassPointer; 
     } 

     ofstream ofs2("serialization2.dat"); 
     boost::archive::binary_oarchive oa(ofs2); 
     //boost::archive::binary_oarchive oa(ofs); 

     for(int i=0;i<5;i++) 
     { 
      AClass* baseClassPointer = new CClass(); 
      // serialize object through base pointer 
      oa << baseClassPointer; 
      // free the pointer so next allocation can reuse memory address 
      delete baseClassPointer; 
     } 
    } 
    getchar(); 
    cout << "Deserializing..." << endl; 
    { 
     ifstream ifs("serialization1.dat"); 
     boost::archive::binary_iarchive ia(ifs); 
     try{ 
      while(true){ 
       AClass* a; 
       ia >> a; 
       delete a; 
      } 
     }catch(boost::archive::archive_exception const& e) 
     { 

     } 

     ifstream ifs2("serialization2.dat"); 
     boost::archive::binary_iarchive ia2(ifs2); 
     try{ 
      while(true){ 
       AClass* a; 
       ia2 >> a; 
       delete a; 
      } 
     }catch(boost::archive::archive_exception const& e) 
     { 

     } 

    } 
    return 0; 
} 


namespace boost { 
namespace archive { 
namespace detail { 

template<> 
    virtual bool oserializer<class binary_oarchive, class AClass >::tracking(const unsigned int f /* flags */) const { 
     return !(f & no_tracking); 
    } 

}}} 

यह अभी भी वह नहीं हो सकता है जिसे आप ढूंढ रहे हैं। ऐसे कई तरीके हैं जिन्हें स्वयं के कार्यान्वयन के साथ अनुकूलित किया जा सकता है। या आपको अपनी खुद की संग्रह कक्षा को व्युत्पन्न करना है।

+0

एक अच्छा दृष्टिकोण होने लगता है! मुझे लगता है कि यह मेरी आवश्यकताओं को पूरा कर सकता है। कल मुझे अधिक विस्तार से अपनी प्रतिक्रिया जांचने और परीक्षण करने दें। मैं आपको वापस बता दूंगा। धन्यवाद! –

+0

@alvarolb मैं थोड़ा उत्सुक हूँ। क्या यह आपके काम आया? –

+0

अंततः मुझे आपके दृष्टिकोण का परीक्षण करने में कुछ समय लगता है, लेकिन ऐसा लगता है कि यह काम नहीं करता है। यह आभासी ट्रैकिंग विधि में एक त्रुटि प्रतीत होता है, क्योंकि यह oserializer वर्ग स्कोप के अंदर नहीं है। "वर्चुअल आउट क्लास घोषणा"। और मैं बूस्ट लाइब्रेरीज़ को संशोधित नहीं कर सकता :( –

2

आखिरकार समस्या यह प्रतीत होती है कि boost::serialization संग्रह समय पर एक बिंदु पर राज्य का प्रतिनिधित्व करता है, और आप चाहते हैं कि आपके संग्रह में राज्य शामिल हो, जो बदल गया है, यानी पॉइंटर्स का पुन: उपयोग किया गया है। मुझे नहीं लगता कि एक साधारण boost::serialization ध्वज है जो आपके इच्छित व्यवहार को प्रेरित करता है।

हालांकि, मुझे लगता है कि अन्य कामकाज पर्याप्त हो सकते हैं। आप कक्षा के लिए अपने संग्रह में क्रमबद्धकरण को समाहित कर सकते हैं, और फिर encapsulation संग्रहित कर सकते हैं। यही कारण है, अगर आप इस तरह B के लिए क्रमांकन लागू कर सकते हैं (ध्यान दें कि आप save() और load() में serialize() विभाजित करने के लिए है कि):

// #include <boost/serialization/split_member.hpp> 
// #include <boost/serialization/string.hpp> 
// Replace serialize() member function with this. 

template<class Archive> 
void save(Archive& ar, const unsigned int version) const { 
    // Serialize instance to a string (or other container). 
    // std::stringstream used here for simplicity. You can avoid 
    // some buffer copying with alternative stream classes that 
    // directly access an external container or iterator range. 
    std::ostringstream os; 
    boost::archive::binary_oarchive oa(os); 
    oa << boost::serialization::base_object<AClass>(*this); 
    oa << c; 
    oa << d; 

    // Archive string to top level. 
    const std::string s = os.str(); 
    ar & s; 
    cout << "B" << endl; 
} 

template<class Archive> 
void load(Archive& ar, const unsigned int version) { 
    // Unarchive string from top level. 
    std::string s; 
    ar & s; 

    // Deserialize instance from string. 
    std::istringstream is(s); 
    boost::archive::binary_iarchive ia(is); 
    ia >> boost::serialization::base_object<AClass>(*this); 
    ia >> c; 
    ia >> d; 
    cout << "B" << endl; 
} 

BOOST_SERIALIZATION_SPLIT_MEMBER() 

क्योंकि B के प्रत्येक उदाहरण के लिए अपने स्वयं के संग्रह में धारावाहिक रूप है, A प्रभावी रूप से ट्रैक नहीं किया है क्योंकि B के प्रति संग्रह में केवल एक संदर्भ है। यह उत्पादित करता है:

Serializing.... 
A 
B 
A 
B 
A 
B 
A 
B 
A 
B 
A 
C 
C 
C 
C 
C 

Deserializing... 
A 
B 
A 
B 
A 
B 
A 
B 
A 
B 
A 
C 
C 
C 
C 
C 

इस तकनीक के लिए एक संभावित आपत्ति encapsulation का संग्रहण ओवरहेड है। मूल परीक्षण कार्यक्रम का परिणाम 319 बाइट्स है जबकि संशोधित परीक्षण कार्यक्रम 664 बाइट उत्पन्न करता है। हालांकि, अगर दोनों आउटपुट फाइलों पर gzip लागू किया गया है तो आकार के लिए मूल और 116 बाइट्स के लिए आकार 113 बाइट हैं।यदि अंतरिक्ष चिंता का विषय है तो मैं बाहरी क्रमिकरण में संपीड़न जोड़ने की अनुशंसा करता हूं, जिसे आसानी से boost::iostreams के साथ किया जा सकता है।

एक और संभावित कामकाज संग्रह के जीवनकाल के उदाहरणों का जीवन विस्तार करना है ताकि पॉइंटर्स का पुन: उपयोग नहीं किया जा सके। आप अपने संग्रह में shared_ptr उदाहरणों के कंटेनर को जोड़कर या मेमोरी पूल से उदाहरण आवंटित करके ऐसा कर सकते हैं।

+0

एक संग्रह को encapsulating के भंडारण ओवरहेड के बारे में एक नोट जोड़ा गया। – rhashimoto

+0

धन्यवाद ... लेकिन यह समाधान क्रमबद्ध प्रक्रिया को जटिल करता है और इसके आकार को भी बढ़ाता है। मैं पॉइंटर्स का जीवन भी बढ़ा सकता हूं क्योंकि सिस्टम अनिश्चित काल तक काम करने का इरादा रखता है। चलो, आपकी मदद के लिए धन्यवाद! –

संबंधित मुद्दे