क्या सी ++ में एक वर्ग को क्रमबद्ध और निर्विवाद करना संभव है?


138

क्या सी ++ में एक वर्ग को क्रमबद्ध और निर्विवाद करना संभव है?

मैं अब 3 साल के लिए जावा का उपयोग कर रहा हूं, और उस भाषा में क्रमबद्धता / deserialization काफी तुच्छ है। क्या C ++ में समान विशेषताएं हैं? क्या देशी पुस्तकालय हैं जो क्रमांकन को संभालते हैं?

एक उदाहरण सहायक होगा।


2
निश्चित नहीं है कि "मूल" से आपका क्या तात्पर्य है, क्या आपका मतलब है देशी C ++ (जैसे Boost.Serialization)? क्या आप केवल C ++ स्टैंडर्ड लाइब्रेरी का उपयोग कर रहे हैं? क्या आपका मतलब कुछ और है?
jwfearn

1
मेरा मतलब है "बाहरी सॉफ़्टवेयर-लाइब्रेरी नहीं"। और खेद है कि मेरी अंग्रेजी बहुत अच्छी नहीं है: एस। मैं अर्जेंटीना से हूँ
अगस्ता-एन

3
किसी वस्तु को क्रमबद्ध करने का मूल तरीका नहीं है (आप अभी भी एक पीओडी से द्विआधारी डेटा को डंप कर सकते हैं, लेकिन आपको वह नहीं मिलेगा जो आप चाहते हैं)। फिर भी, बूस्ट, जबकि "आंतरिक पुस्तकालय" नहीं है, पहला बाहरी पुस्तकालय है जिसे आपको अपने संकलक में जोड़ना चाहिए। बूस्ट एसटीएल क्वालिटी का है (यानी टॉप गन सी ++)
पियर्सबल

जवाबों:


95

Boost::serializationपुस्तकालय इस बल्कि सुंदर ढंग से संभालती है। मैंने कई परियोजनाओं में इसका उपयोग किया है। यहां एक उदाहरण कार्यक्रम है, जिसमें दिखाया गया है कि इसका उपयोग कैसे किया जाता है

इसे करने का एकमात्र मूल तरीका धाराओं का उपयोग करना है। यह अनिवार्य रूप से सभी Boost::serializationपुस्तकालय करता है, यह एक पाठ की तरह प्रारूप में वस्तुओं को लिखने और उन्हें एक ही प्रारूप से पढ़ने के लिए एक रूपरेखा स्थापित करके धारा पद्धति का विस्तार करता है।

अंतर्निहित प्रकारों के लिए, या अपने स्वयं के प्रकारों के साथ operator<<और operator>>ठीक से परिभाषित, यह काफी सरल है; देखना सी ++ पूछे जाने वाले प्रश्न अधिक जानकारी के लिए।


यह मुझे लगता है कि बढ़ावा :: क्रमांकन के लिए कॉल करने वाले को उस आदेश का ट्रैक रखने की आवश्यकता होती है जिसमें ऑब्जेक्ट लिखे और पढ़े जाते हैं। क्या वो सही है? इसलिए यदि किसी प्रोग्राम के संस्करणों के बीच उस क्रम में बदलाव होता है, जिसमें दो फ़ील्ड लिखे गए हैं, तो हमारी असंगतता है। क्या यह सही है?
एगेल कुरियन

1
यह शायद सीरियलिंग फंक्शन्स के कारण होगा, न कि बूस्ट :: सीरियलाइजेशन कोड ही।
हेड गीक

1
@ 0xDEADBEEF: यह शायद बाइनरी_ (i। O) संग्रह का उपयोग करते समय बहुत खुशी देता है, जो एंडियन-नेस जैसी अन्य "समस्याओं" का परिचय देता है। टेक्स्ट_ (i | o) संग्रह को आज़माएं, यह अधिक प्लेटफॉर्म अज्ञेयवादी है।
इला .२ El२

2
एक विशिष्ट framwork / पुस्तकालय समाधान स्वीकार किए जाते हैं जवाब नहीं होना चाहिए।
एंड्रिया

3
@Andrea: बूस्ट लाइब्रेरी एक विशेष मामला है। C ++ 11 को अंतिम रूप दिए जाने तक, इसके बिना आधुनिक C ++ कोड लिखना सभी असंभव था, लेकिन यह एक अलग एसटीएल की तुलना में द्वितीयक STL के करीब था।
हेड गीक

52

मुझे लगता है कि यह एक पुरानी पोस्ट है लेकिन यह पहली खोज है जो खोजते समय सामने आती है c++ serialization

मैं किसी को भी प्रोत्साहित करता हूं, जिनके पास अनाज को देखने के लिए C ++ 11 तक पहुंच है , सी + 11 हेडर केवल पुस्तकालय के लिए क्रमांकन के लिए है जो बाइनरी, JSON और XML को बॉक्स से बाहर का समर्थन करता है। अनाज को विस्तार और उपयोग के लिए आसान बनाया गया था और बूस्ट के समान सिंटैक्स है।


4
अनाज के बारे में अच्छी बात यह है कि बढ़ावा के विपरीत, इसमें न्यूनतम मेटाडेटा (लगभग कोई नहीं) है। बढ़ावा देना :: सीरियलाइज़ेशन वास्तव में कष्टप्रद हो जाता है जब हर बार जब आप एक आर्काइव खोलते हैं, तो यह स्ट्रीम के लिए अपने काम का संस्करण लिखता है, जो किसी फ़ाइल को असंभव बना देता है।
साइबरसोनॉपी

@CyberSnoopy - एक संग्रह बनने पर इस सुविधा को दबाने के लिए एक ध्वज है - निश्चित रूप से आपको संग्रह को पढ़ने के दौरान भी इसे याद रखना होगा।
राबर्ट रमी

16

बूस्ट एक अच्छा सुझाव है। लेकिन अगर आप अपना रोल करना चाहते हैं, तो यह इतना मुश्किल नहीं है।

मूल रूप से आपको बस वस्तुओं के ग्राफ को बनाने के लिए एक तरीका चाहिए और फिर उन्हें कुछ संरचित भंडारण प्रारूप (JSON, XML, YAML, जो भी हो) में आउटपुट करना होगा। ग्राफ को बनाना उतना ही सरल है जितना कि एक चिन्हित पुनरावर्ती सभ्य वस्तु एल्गोरिथ्म का उपयोग करना और फिर सभी चिह्नित वस्तुओं को आउटपुट करना।

मैंने एक अल्पविकसित (लेकिन अभी भी शक्तिशाली) क्रमबद्धता प्रणाली का वर्णन करते हुए एक लेख लिखा। आपको यह दिलचस्प लग सकता है: ऑन-डिस्क फ़ाइल प्रारूप, भाग 2 के रूप में SQLite का उपयोग करना


14

जहां तक ​​"बिल्ट-इन" लाइब्रेरी जाते हैं, <<और >>विशेष रूप से क्रमांकन के लिए आरक्षित किए गए हैं।

आपको <<अपनी वस्तु को कुछ क्रमांकन संदर्भ (आमतौर पर iostream) और >>उस संदर्भ से डेटा वापस पढ़ने के लिए आउटपुट करना चाहिए । प्रत्येक वस्तु अपने समेकित बाल वस्तुओं के उत्पादन के लिए जिम्मेदार है।

यह विधि तब तक ठीक काम करती है जब तक कि आपके ऑब्जेक्ट ग्राफ में कोई चक्र न हो।

यदि ऐसा होता है, तो आपको उन चक्रों से निपटने के लिए एक पुस्तकालय का उपयोग करना होगा।


3
निश्चित रूप से, यह सही नहीं हो सकता ... लागू किए गए <<ऑपरेटरों का उपयोग वस्तुओं के मानव-पठनीय पाठ अभ्यावेदन को प्रिंट करने के लिए किया जाता है, जो कि अक्सर आप क्रमबद्धता के लिए नहीं चाहते हैं।
einpoklum

1
@einpoklum <<जेनेरिक के लिए परिभाषित करने के बजाय ostream, इसे फ़ाइल स्ट्रीम के लिए परिभाषित करने का प्रयास करें।
कैरिजिनेट

1
@Carcigenicate: एक लॉग फ़ाइल जो मानव-पठनीय पाठ को लेती है वह एक फ़ाइल स्ट्रीम है।
einpoklum

1
@einpoklum मुझे पूरा यकीन नहीं है कि आपका क्या मतलब है। फ्रैंक का अधिकार हालांकि, उन ऑपरेटरों को धारावाहिक करने के लिए इस्तेमाल किया जा सकता है। मैंने उन्हें एक वेक्टर को क्रमबद्ध / deserialize करने के लिए परिभाषित किया है।
कैरिजनेट

2
मुझे लगता है कि कैच यहां है "आपको <<अपनी वस्तु को कुछ क्रमांकन संदर्भ में आउटपुट करना चाहिए ... प्रत्येक ऑब्जेक्ट इसके उत्पादन के लिए जिम्मेदार है ..." - सवाल यह है कि प्रत्येक वस्तु के लिए श्रमसाध्य रूप से लिखने से कैसे बचें: कितना हो सकता है भाषा या पुस्तकालय मदद करते हैं?
श्रीवत्सआर

14

मैं Google प्रोटोकॉल बफ़र्स की सलाह देता हूं । मेरे पास एक नए प्रोजेक्ट पर लाइब्रेरी का परीक्षण करने का मौका था और यह उल्लेखनीय रूप से उपयोग करना आसान है। लाइब्रेरी को प्रदर्शन के लिए भारी अनुकूलित किया गया है।

प्रोटोबुफ़ अन्य क्रमिक समाधानों से अलग है, जिसका उल्लेख यहाँ इस अर्थ में किया गया है कि यह आपकी वस्तुओं को क्रमबद्ध नहीं करता है, बल्कि आपके विनिर्देशन के अनुसार क्रमबद्धता वाली वस्तुओं के लिए कोड उत्पन्न करता है।


2
क्या आपको इसका उपयोग करते हुए 10-50MB आकार की वस्तुओं को क्रमबद्ध करने का अनुभव है? दस्तावेज़ीकरण यह कहता प्रतीत होता है कि प्रोटोकॉल बफ़र्स एमबी के आकार की वस्तुओं के लिए सबसे उपयुक्त हैं।
एगेल कुरियन

मैंने अपनी खुद की लिबास को रोल किया, धाराओं (अभी तक) का उपयोग नहीं करता है, इसलिए यह वास्तव में छोटी चीजों के लिए है: लीब को gist.github.com/earonesty/5ba3a93f391ea03ef90884840f068767
Erik Aronesty

13

बूस्ट :: सीरियलाइजेशन एक बेहतरीन विकल्प है, लेकिन मैंने एक नई परियोजना का सामना किया है: अनाज जो मुझे बहुत अधिक सुंदर लगता है! मैं इसकी जांच करने का अत्यधिक सुझाव देता हूं।


4

आप जांच कर सकते हैं amef प्रोटोकॉल की am ++ में C ++ एन्कोडिंग का एक उदाहरण होगा,

    //Create a new AMEF object
    AMEFObject *object = new AMEFObject();

    //Add a child string object
    object->addPacket("This is the Automated Message Exchange Format Object property!!","adasd");   

    //Add a child integer object
    object->addPacket(21213);

    //Add a child boolean object
    object->addPacket(true);

    AMEFObject *object2 = new AMEFObject();
    string j = "This is the property of a nested Automated Message Exchange Format Object";
    object2->addPacket(j);
    object2->addPacket(134123);
    object2->addPacket(false);

    //Add a child character object
    object2->addPacket('d');

    //Add a child AMEF Object
    object->addPacket(object2);

    //Encode the AMEF obejct
    string str = new AMEFEncoder()->encode(object,false);

जावा में डिकोडिंग जैसा होगा,

    string arr = amef encoded byte array value;
    AMEFDecoder decoder = new AMEFDecoder()
    AMEFObject object1 = AMEFDecoder.decode(arr,true);

प्रोटोकॉल कार्यान्वयन में C ++ और Java दोनों के लिए कोडेक्स होते हैं, दिलचस्प बात यह है कि यह नाम मूल्य जोड़े के रूप में ऑब्जेक्ट क्लास प्रतिनिधित्व को बनाए रख सकता है, मुझे अपने आखिरी प्रोजेक्ट में इसी तरह के प्रोटोकॉल की आवश्यकता थी, जब मैं गलती से इस प्रोटोकॉल पर ठोकर खाई थी, तो मैं वास्तव में था मेरी आवश्यकताओं के अनुसार बेस लाइब्रेरी को संशोधित किया। आशा है कि यह आपकी मदद करता है।


3

मैं अन्य पोस्टरों द्वारा वर्णित बढ़ावा क्रमांकन का उपयोग करने की सलाह देता हूं। यहाँ इसका उपयोग करने के बारे में एक अच्छा विस्तृत ट्यूटोरियल है जो बूस्ट ट्यूटोरियल को अच्छी तरह से पूरक करता है: http://www.ocoudert.com/blog/2011/07/09/a-practical-guide-to-c-serialization/


3

स्वीट पर्सिस्ट एक और है।

XML, JSON, Lua और बाइनरी फॉर्मेट में स्ट्रीम से और इससे सीरियल करना संभव है।


यह साइट नीचे की ओर लगती है, सभी मुझे मिल सकते हैं यह पुराना रेपो था: github.com/cwbaker/sweet_persist
Janusz Syf

2

मेरा सुझाव है कि सार कारखानों को देखा जाए जो अक्सर क्रमबद्धता के आधार के रूप में उपयोग किए जाते हैं

मैंने C ++ कारखानों के बारे में एक और SO प्रश्न में उत्तर दिया है। कृपया देखें कि क्या कोई लचीली फैक्ट्री ब्याज की है। मैं मैक्रो का उपयोग करने के लिए ईटी ++ से एक पुराने तरीके का वर्णन करने की कोशिश करता हूं जिसने मेरे लिए बहुत अच्छा काम किया है।

ET ++ पुराने MacApp को C ++ और X11 पोर्ट करने का प्रोजेक्ट था। इसके प्रयास में एरिक गामा आदि ने डिज़ाइन पैटर्न के बारे में सोचना शुरू किया । ET ++ में क्रमबद्धता और आत्मनिरीक्षण के लिए स्वचालित तरीके निहित थे।


0

यदि आप सरल और सर्वश्रेष्ठ प्रदर्शन चाहते हैं और पिछड़े डेटा संगतता के बारे में परवाह नहीं करते हैं, तो एचपीएस का प्रयास करें , तो , यह हल्का है, बूस्ट की तुलना में बहुत तेज है, आदि, और प्रोटोबुफ़ की तुलना में उपयोग करने के लिए बहुत आसान है, आदि।

उदाहरण:

std::vector<int> data({22, 333, -4444});
std::string serialized = hps::serialize_to_string(data);
auto parsed = hps::parse_from_string<std::vector<int>>(serialized);

0

यहाँ एक साधारण सी धारावाहिक पुस्तकालय है जिसे मैंने खटखटाया। यह केवल हेडर है, c11 और इसमें बुनियादी प्रकारों को क्रमबद्ध करने के लिए उदाहरण हैं। यहाँ एक मैप टू क्लास है।

https://github.com/goblinhack/simple-c-plus-plus-serializer

#include "c_plus_plus_serializer.h"

class Custom {
public:
    int a;
    std::string b;
    std::vector c;

    friend std::ostream& operator<<(std::ostream &out, 
                                    Bits my)
    {
        out << bits(my.t.a) << bits(my.t.b) << bits(my.t.c);
        return (out);
    }

    friend std::istream& operator>>(std::istream &in, 
                                    Bits my)
    {
        in >> bits(my.t.a) >> bits(my.t.b) >> bits(my.t.c);
        return (in);
    }

    friend std::ostream& operator<<(std::ostream &out, 
                                    class Custom &my)
    {
        out << "a:" << my.a << " b:" << my.b;

        out << " c:[" << my.c.size() << " elems]:";
        for (auto v : my.c) {
            out << v << " ";
        }
        out << std::endl;

        return (out);
    }
};

static void save_map_key_string_value_custom (const std::string filename)
{
    std::cout << "save to " << filename << std::endl;
    std::ofstream out(filename, std::ios::binary );

    std::map< std::string, class Custom > m;

    auto c1 = Custom();
    c1.a = 1;
    c1.b = "hello";
    std::initializer_list L1 = {"vec-elem1", "vec-elem2"};
    std::vector l1(L1);
    c1.c = l1;

    auto c2 = Custom();
    c2.a = 2;
    c2.b = "there";
    std::initializer_list L2 = {"vec-elem3", "vec-elem4"};
    std::vector l2(L2);
    c2.c = l2;

    m.insert(std::make_pair(std::string("key1"), c1));
    m.insert(std::make_pair(std::string("key2"), c2));

    out << bits(m);
}

static void load_map_key_string_value_custom (const std::string filename)
{
    std::cout << "read from " << filename << std::endl;
    std::ifstream in(filename);

    std::map< std::string, class Custom > m;

    in >> bits(m);
    std::cout << std::endl;

    std::cout << "m = " << m.size() << " list-elems { " << std::endl;
    for (auto i : m) {
        std::cout << "    [" << i.first << "] = " << i.second;
    }
    std::cout << "}" << std::endl;
}

void map_custom_class_example (void)
{
    std::cout << "map key string, value class" << std::endl;
    std::cout << "============================" << std::endl;
    save_map_key_string_value_custom(std::string("map_of_custom_class.bin"));
    load_map_key_string_value_custom(std::string("map_of_custom_class.bin"));
    std::cout << std::endl;
}

आउटपुट:

map key string, value class
============================
save to map_of_custom_class.bin
read from map_of_custom_class.bin

m = 2 list-elems {
    [key1] = a:1 b:hello c:[2 elems]:vec-elem1 vec-elem2
    [key2] = a:2 b:there c:[2 elems]:vec-elem3 vec-elem4
}

0

मैं क्रमांकन लागू करने के लिए निम्नलिखित टेम्पलेट का उपयोग कर रहा हूं:

template <class T, class Mode = void> struct Serializer
{
    template <class OutputCharIterator>
    static void serializeImpl(const T &object, OutputCharIterator &&it)
    {
        object.template serializeThis<Mode>(it);
    }

    template <class InputCharIterator>
    static T deserializeImpl(InputCharIterator &&it, InputCharIterator &&end)
    {
        return T::template deserializeFrom<Mode>(it, end);
    }
};

template <class Mode = void, class T, class OutputCharIterator>
void serialize(const T &object, OutputCharIterator &&it)
{
    Serializer<T, Mode>::serializeImpl(object, it);
}

template <class T, class Mode = void, class InputCharIterator>
T deserialize(InputCharIterator &&it, InputCharIterator &&end)
{
    return Serializer<T, Mode>::deserializeImpl(it, end);
}

template <class Mode = void, class T, class InputCharIterator>
void deserialize(T &result, InputCharIterator &&it, InputCharIterator &&end)
{
    result = Serializer<T, Mode>::deserializeImpl(it, end);
}

यहाँ Tप्रकार है जिसे आप क्रमबद्ध करना चाहते हैं Mode, विभिन्न प्रकार के क्रमांकन के बीच अंतर करने के लिए एक डमी प्रकार है, जैसे। एक ही पूर्णांक को छोटे एंडियन, बड़े एंडियन, वेरिंट आदि के रूप में क्रमबद्ध किया जा सकता है।

डिफ़ॉल्ट रूप से Serializerप्रतिनिधि को ऑब्जेक्ट को क्रमबद्ध किया जा रहा है। बिल्ट इन टाइप्स के लिए आपको एक खाका बनाना चाहिए Serializer

सुविधा फ़ंक्शन टेम्पलेट भी प्रदान किए जाते हैं।

उदाहरण के लिए अहस्ताक्षरित पूर्णांक के छोटे एंडियन क्रमांकन:

struct LittleEndianMode
{
};

template <class T>
struct Serializer<
    T, std::enable_if_t<std::is_unsigned<T>::value, LittleEndianMode>>
{
    template <class InputCharIterator>
    static T deserializeImpl(InputCharIterator &&it, InputCharIterator &&end)
    {
        T res = 0;

        for (size_t i = 0; i < sizeof(T); i++)
        {
            if (it == end) break;
            res |= static_cast<T>(*it) << (CHAR_BIT * i);
            it++;
        }

        return res;
    }

    template <class OutputCharIterator>
    static void serializeImpl(T number, OutputCharIterator &&it)
    {
        for (size_t i = 0; i < sizeof(T); i++)
        {
            *it = (number >> (CHAR_BIT * i)) & 0xFF;
            it++;
        }
    }
};

फिर क्रमबद्ध करने के लिए:

std::vector<char> serialized;
uint32_t val = 42;
serialize<LittleEndianMode>(val, std::back_inserter(serialized));

Deserialize करने के लिए:

uint32_t val;
deserialize(val, serialized.begin(), serialized.end());

अमूर्त पुनरावृत्ति तर्क के कारण, इसे किसी भी पुनरावृत्त (जैसे। स्ट्रीम पुनरावृत्तियों), सूचक आदि के साथ काम करना चाहिए।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.