Boost logo

Boost Users :

From: Bill Lear (rael_at_[hidden])
Date: 2005-02-19 21:50:05


On Saturday, February 19, 2005 at 13:58:07 (-0600) Bill Lear writes:
>I have a long question on how to combine a Singleton factory, serialization,
>shared pointers and an object hierarchy half of which will be created
>by a factory, and half of which will not.

Ok, this took so long to show up that I solved the problem, although
someone else may have a better solution.

Here is a (working) sketch of my solution, below my sig, if anyone is
interested.

Bill

#include <string>
#include <iostream>
#include <fstream>
#include <map>

using namespace std;

#include <boost/serialization/shared_ptr.hpp>
#include <boost/serialization/utility.hpp>
#include <boost/serialization/nvp.hpp>
#include <boost/archive/xml_iarchive.hpp>
#include <boost/archive/xml_oarchive.hpp>
#include <boost/serialization/export.hpp>
#include <boost/serialization/split_member.hpp>
#include <boost/shared_ptr.hpp>

using namespace boost;

class Base {
public:
    const string& key() const { return _key; }

    virtual void foo() {
        cout << "Base::foo(): key is [" << key() << "]\n";
    }

    virtual ~Base() { cout << "~iDataSTream()\n"; }

protected:
    Base(const string& key = "") : _key(key) {
    }

private:
    string _key;

    friend class boost::serialization::access;

    template<class Archive>
    void serialize(Archive& ar, const unsigned int) {
        ar & BOOST_SERIALIZATION_NVP(_key);
    }
};

BOOST_CLASS_EXPORT(Base);

typedef shared_ptr<Base> BasePtrBase;

class Factory;

class BasePtr : public BasePtrBase {
public:
    BasePtr() {}

    BasePtr(const BasePtr& p) : BasePtrBase(p) {}
    BasePtr(Base* p) : BasePtrBase(p) {}

private:
    friend class boost::serialization::access;

    template <class Archive>
    void BasePtr::save(Archive& ar, unsigned int) const {
        Base* my_ds = get();

        bool flag = my_ds->key().size() != 0;

        ar << BOOST_SERIALIZATION_NVP(flag);

        if (flag) {
            string key = my_ds->key();
            ar << BOOST_SERIALIZATION_NVP(key);
        } else {
            ar << BOOST_SERIALIZATION_NVP(my_ds);
        }
    }

    template <class Archive>
    void BasePtr::load(Archive& ar, unsigned int) {
        bool flag;

        ar >> BOOST_SERIALIZATION_NVP(flag);

        Base* my_ds;

        if (flag) {
            string key;
            ar >> BOOST_SERIALIZATION_NVP(key);
            *this = Factory::create(key);
        } else {
            ar >> BOOST_SERIALIZATION_NVP(my_ds);
            *this = BasePtr(my_ds);
        }
    }

    BOOST_SERIALIZATION_SPLIT_MEMBER()
};

BOOST_SHARED_POINTER_EXPORT(BasePtr);

class Derived : public Base {
public:
    virtual void foo() {
        cout << "Derived::foo(): key is [" << key() << "]\n";
    }

    virtual ~Derived() { cout << "~Derived()\n"; }

    static BasePtr alloc(string key) {
        return BasePtr(new Derived(key));
    }
private:
    Derived(const string& key) : Base(key) {}
};

class DerivedII : public Base {
public:
    virtual void foo() {
        cout << "DerivedII::foo(): key is [" << key() << "]\n";
    }

    virtual ~DerivedII() { cout << "~DerivedII()\n"; }

    static BasePtr alloc(const string& key) {
        return BasePtr(new DerivedII(key));
    }
private:
    DerivedII(const string& key) : Base(key) {}
};

class DerivedTest : public Base {
public:
    virtual void foo() {
        cout << "DerivedTest::foo(): key is [" << key() << "]\n";
    }

    virtual ~DerivedTest() { cout << "~DerivedTest()\n"; }

    static BasePtr alloc() {
        return BasePtr(new DerivedTest);
    }
private:
    DerivedTest() {}

    friend class boost::serialization::access;

    template<class Archive>
    void serialize(Archive& ar, const unsigned int) {
        ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(Base);
    }
};

BOOST_CLASS_EXPORT(DerivedTest);

typedef map<string, BasePtr> BaseMap;

class Factory {
public:
    static BasePtr create(string key) {
        BaseMap::iterator i = ds_map.find(key);

        if (i != ds_map.end()) {
            return i->second;
        }

        BasePtr p;

        if (key == "I") {
            p = Derived::alloc(key);
        } else {
            p = DerivedII::alloc(key);
        }

        ds_map[key] = p;

        return p;
    }
private:
    static BaseMap ds_map;
};

BaseMap Factory::ds_map;

BasePtr doit() {
    {
        BasePtr production(Factory::create("I"));
        BasePtr productionII(Factory::create("II"));
        BasePtr test(DerivedTest::alloc());

        ofstream out("srl.xml");

        archive::xml_oarchive oa(out);

        oa & BOOST_SERIALIZATION_NVP(production);
        oa & BOOST_SERIALIZATION_NVP(test);
        oa & BOOST_SERIALIZATION_NVP(productionII);
    }

    BasePtr ds1;
    BasePtr ds2;
    BasePtr ds3;

    {
        ifstream in("srl.xml");
        archive::xml_iarchive ia(in);

        ia & BOOST_SERIALIZATION_NVP(ds1);
        ia & BOOST_SERIALIZATION_NVP(ds2);
        ia & BOOST_SERIALIZATION_NVP(ds3);

        ds1->foo();
        ds2->foo();
        ds3->foo();

        {
            BasePtr dsA = ds1;
            dsA->foo();

            BasePtr dsB = ds1;
            dsB->foo();

            BasePtr dsC = ds1;
            dsC->foo();
        }
    }

    return ds1;
}

int main() {
    {
        BasePtr ds = doit();

        cout << "In main:\n";
        ds->foo();
        cout << "done with main scope\n";
    }
    cout << "After main scope\n";
}


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net