Boost serialization - abstrakte Klasse "templates may not be virtual"



  • Naja du registrierst ja nirgends deine Klassen. Dann kann polymorphe Serialisierung natürlich auch nicht gehen - zumindest nicht mit Boost.Serialization.
    Steht ja alles in den von @Th69 und mir verlinkten Seiten.

    Weiters ist IMO was du mit ss & *audi.get(); machst Quatsch. Wenn du eh schon weisst dass es ein Audi ist, wozu dann der Zeiger? Und wenn du es nicht weisst, dann solltest du auch besser die Pointer serialisieren und nicht die Objekte direkt. Weil dir Boost.Serialization dann anhand der Daten im Archiv automatisch den passenden Typ erstellt.

    Deine Klassen registrieren musst du aber natürlich trotzdem. Entweder statich über BOOST_CLASS_EXPORT oder dynamisch über register_type.



  • Danke für die weitere Erklärung. Warum kann das Beispiel von Th69 (verlinkte Seite - erstes Beispiel) ohne das Registrieren gehen? Ich habe

    BOOST_CLASS_EXPORT(Audi)
    BOOST_CLASS_EXPORT(Porsche)
    

    zu dem Code hinzugefügt aber ich kriege einen ähnlichen Fehler:

    terminate called after throwing an instance of 'boost::archive::archive_exception'
      what():  input stream error
    [1]    8134 abort      ./a.out
    
    

    Und auch zu deinem Punkt bzgl ss & *audi.get(). Ich habe den Code ohne den Zeiger ausprobiert und ich bekomme diese Fehler:

    virt_funk_seri.cpp: In function ‘int main()’:
    virt_funk_seri.cpp:155:22: error: invalid initialization of non-const reference of type ‘Audi*&’ from an rvalue of type ‘std::unique_ptr<Audi, std::default_delete<Audi> >::pointer {aka Audi*}’
             ss & audi.get();
                  ~~~~~~~~^~
    In file included from /usr/include/boost/archive/detail/common_iarchive.hpp:23:0,
                     from /usr/include/boost/archive/basic_binary_iarchive.hpp:30,
                     from /usr/include/boost/archive/binary_iarchive_impl.hpp:21,
                     from /usr/include/boost/archive/binary_iarchive.hpp:20,
                     from virt_funk_seri.cpp:3:
    /usr/include/boost/archive/detail/interface_iarchive.hpp:74:15: note:   initializing argument 1 of ‘Archive& boost::archive::detail::interface_iarchive<Archive>::operator&(T&) [with T = Audi*; Archive = boost::archive::binary_iarchive]’
         Archive & operator&(T & t){
                   ^~~~~~~~
    virt_funk_seri.cpp:156:25: error: invalid initialization of non-const reference of type ‘Porsche*&’ from an rvalue of type ‘std::unique_ptr<Porsche, std::default_delete<Porsche> >::pointer {aka Porsche*}’
             ss & porsche.get();
                  ~~~~~~~~~~~^~
    In file included from /usr/include/boost/archive/detail/common_iarchive.hpp:23:0,
                     from /usr/include/boost/archive/basic_binary_iarchive.hpp:30,
                     from /usr/include/boost/archive/binary_iarchive_impl.hpp:21,
                     from /usr/include/boost/archive/binary_iarchive.hpp:20,
                     from virt_funk_seri.cpp:3:
    /usr/include/boost/archive/detail/interface_iarchive.hpp:74:15: note:   initializing argument 1 of ‘Archive& boost::archive::detail::interface_iarchive<Archive>::operator&(T&) [with T = Porsche*; Archive = boost::archive::binary_iarchive]’
         Archive & operator&(T & t){
    
    

    Danke nochmal für die Hilfe!!



  • @mika000 sagte in Boost serialization - abstrakte Klasse "templates may not be virtual":

    ss & audi.get();

    Das ist doch nicht "ohne Zeiger". Ohne Zeiger wäre

    Audi audi{ ... };
    archive & audi;
    

    Ansonsten kannst du noch probieren

       {
            std::unique_ptr<Car> audi = std::make_unique<Audi>("Wilma", 3, "Rene", "Argentina" ,arma::randu<arma::mat>(4,5));
            audi->getInfo();
    
            std::unique_ptr<Car> porsche = std::make_unique<Porsche>("Joe", 14, arma::randu<arma::mat>(6,5));
            porsche->getInfo();
    
            std::ofstream outputStream("bin.dat", std::ios::binary);
            boost::archive::binary_oarchive ar(outputStream);
            ar & audi;
            ar & porsche;
        }
    
        {
            std::unique_ptr<Car> audi;
            std::unique_ptr<Car> porsche;
    
            std::ifstream inputStream("bin.dat", std::ios::binary);
            boost::archive::binary_iarchive ar(inputStream);
            ar & audi;
            ar & porsche;
    
            audi->getInfo();
            porsche->getInfo();   
        }
    

    Und übrigens fehlt deiner Car Klasse auch ein virtueller Destruktor. Ohne werden in deinem Beispiel die konkreten Objekte nicht korrekt zerstört, da du sie ja über Car-Zeiger löscht.



  • Hallo zusammen,

    ich stehe auf dem Schlauch. Mit Hilfe von hustbaer und Th69 kam ich definitiv weiter aber ich bekomme trotzdem noch den gleichen Fehler wie oben. Hier ist der Code:

    #include <armadillo>
    
    #include <boost/archive/binary_iarchive.hpp>
    #include <boost/archive/binary_oarchive.hpp>
    #include <boost/serialization/assume_abstract.hpp>
    #include <boost/serialization/serialization.hpp>
    #include <boost/serialization/split_member.hpp>
    #include <boost/serialization/export.hpp>
    
    #include <fstream>
    #include <iostream>
    #include <memory>
    #include <sstream>
    #include <vector>
    
    BOOST_SERIALIZATION_ASSUME_ABSTRACT(Car); //Tell Boost that Car is abstract
    
    //Serialization for Armadillo Matrices------------------
    BOOST_SERIALIZATION_SPLIT_FREE(arma::mat)
    namespace boost::serialization {
        template<class Archive>
        void save(Archive & ar, const arma::mat &t, unsigned int version) {
            ar << t.n_elem;
            auto data = t.colptr(0);
            for (size_t K = 0; K < t.n_elem; ++K)
                ar << data[K];
        }
    
        template<class Archive>
        void load(Archive & ar, arma::mat &t, unsigned int version) {
            size_t n_elem;
            ar >> n_elem;
            t.set_size(n_elem);
            t.zeros();
            auto data = t.colptr(0);
            for (size_t K = 0; K < n_elem; ++K)
                ar >> data[K];
        }
    } // -----------------------------------------
    
    class Car {
    public:
        Car() = default;
        virtual double getInfo() = 0;
        virtual ~Car() = default;
    private:
        friend class boost::serialization::access;
        template <typename Archive>
        void serialize(Archive& ar, unsigned int version) {};
    };
    
    class Porsche : public Car {
    public:
        double getInfo() override { return 1.1; }
        Porsche(std::string owner1, int hp1, arma::mat A1)
            {
            owner = owner1;
            hp = hp1;
            A = A1; 
            
            }
        std::string owner;
        int hp{};
        arma::mat A;
        Porsche() = default;
    private:
        friend class boost::serialization::access;
        template <typename Archive>
        void serialize(Archive& ar, unsigned int) {
            ar & boost::serialization::base_object<Car>(*this); //https://theboostcpplibraries.com/boost.serialization-class-hierarchies
            ar & owner;
            ar & hp;
            ar & A;
        }    
    
        
    };
    
    class Audi : public Car {
    public:
        double getInfo() override { return 2; }
        Audi(std::string owner1, int hp1, std::string second_owner1, std::string country1,  arma::mat A1)
            {
            owner = owner1;
            hp = hp1;
            second_owner = second_owner1; 
            country = country1;
            A = A1; 
            }
        Audi() = default;
    
        std::string owner;
        int hp{};
        std::string second_owner;
        std::string country;
        arma::mat A;
    
    private:
        friend class boost::serialization::access;
        template <typename Archive>
        void serialize(Archive& ar, unsigned int) {
            ar & boost::serialization::base_object<Car>(*this); //https://theboostcpplibraries.com/boost.serialization-class-hierarchies
            ar & owner;
            ar & hp;
            ar & second_owner;
            ar & country;
            ar & A;
        }
    
    };
    
    BOOST_CLASS_EXPORT(Audi)
    BOOST_CLASS_EXPORT(Porsche)
    
    
    int main() {
       {
            std::unique_ptr<Car> audi = std::make_unique<Audi>("Wilma", 3, "Rene", "Argentina" ,arma::randu<arma::mat>(4,5));
            audi->getInfo();
    
            std::unique_ptr<Car> porsche = std::make_unique<Porsche>("Joe", 14, arma::randu<arma::mat>(6,5));
    
            porsche->getInfo();
            std::ofstream outputStream("bin.dat", std::ios::binary);
            boost::archive::binary_oarchive ss(outputStream);
            ss & *audi.get();
            ss & *porsche.get();
        }
    
        {
            std::unique_ptr<Audi> audi = std::make_unique<Audi>();
            std::unique_ptr<Porsche>porsche = std::make_unique<Porsche>();
    
            std::ifstream inputStream("bin.dat", std::ios::binary);
            boost::archive::binary_iarchive ss(inputStream);
            ss & *audi.get();
            ss & *porsche.get();
    
            std::cout << "audi: hp=" << audi->hp << "\n";
            std::cout << "porsche: hp=" << porsche->hp<< " owner=" << porsche->owner << " A=" << porsche->A <<"\n";
    
        }
        
    }
    

    @hustbaer ich habe den Code von deinem letzten Beitrag ausprobiert und ich bekomme folgende Fehler:

    In file included from /usr/include/boost/serialization/split_member.hpp:23:0,
                     from /usr/include/boost/serialization/nvp.hpp:26,
                     from /usr/include/boost/serialization/array.hpp:19,
                     from /usr/include/boost/archive/basic_binary_iprimitive.hpp:53,
                     from /usr/include/boost/archive/binary_iarchive_impl.hpp:20,
                     from /usr/include/boost/archive/binary_iarchive.hpp:20,
                     from virt_funk_seri.cpp:3:
    /usr/include/boost/serialization/access.hpp: In instantiation of ‘static void boost::serialization::access::serialize(Archive&, T&, unsigned int) [with Archive = boost::archive::binary_oarchive; T = std::unique_ptr<Car>]’:
    /usr/include/boost/serialization/serialization.hpp:68:22:   required from ‘void boost::serialization::serialize(Archive&, T&, unsigned int) [with Archive = boost::archive::binary_oarchive; T = std::unique_ptr<Car>]’
    /usr/include/boost/serialization/serialization.hpp:126:14:   required from ‘void boost::serialization::serialize_adl(Archive&, T&, unsigned int) [with Archive = boost::archive::binary_oarchive; T = std::unique_ptr<Car>]’
    /usr/include/boost/archive/detail/oserializer.hpp:149:40:   required from ‘void boost::archive::detail::oserializer<Archive, T>::save_object_data(boost::archive::detail::basic_oarchive&, const void*) const [with Archive = boost::archive::binary_oarchive; T = std::unique_ptr<Car>]’
    /usr/include/boost/archive/detail/oserializer.hpp:102:1:   required from ‘class boost::archive::detail::oserializer<boost::archive::binary_oarchive, std::unique_ptr<Car> >’
    /usr/include/boost/archive/detail/oserializer.hpp:254:13:   required from ‘static void boost::archive::detail::save_non_pointer_type<Archive>::save_standard::invoke(Archive&, const T&) [with T = std::unique_ptr<Car>; Archive = boost::archive::binary_oarchive]’
    /usr/include/boost/archive/detail/oserializer.hpp:309:22:   [ skipping 2 instantiation contexts, use -ftemplate-backtrace-limit=0 to disable ]
    /usr/include/boost/archive/detail/common_oarchive.hpp:70:22:   required from ‘void boost::archive::detail::common_oarchive<Archive>::save_override(T&) [with T = const std::unique_ptr<Car>; Archive = boost::archive::binary_oarchive]’
    /usr/include/boost/archive/basic_binary_oarchive.hpp:80:7:   required from ‘void boost::archive::basic_binary_oarchive<Archive>::save_override(const T&) [with T = std::unique_ptr<Car>; Archive = boost::archive::binary_oarchive]’
    /usr/include/boost/archive/binary_oarchive_impl.hpp:59:9:   required from ‘void boost::archive::binary_oarchive_impl<Archive, Elem, Tr>::save_override(T&) [with T = const std::unique_ptr<Car>; Archive = boost::archive::binary_oarchive; Elem = char; Tr = std::char_traits<char>]’
    /usr/include/boost/archive/detail/interface_oarchive.hpp:70:9:   required from ‘Archive& boost::archive::detail::interface_oarchive<Archive>::operator<<(const T&) [with T = std::unique_ptr<Car>; Archive = boost::archive::binary_oarchive]’
    /usr/include/boost/archive/detail/interface_oarchive.hpp:77:32:   required from ‘Archive& boost::archive::detail::interface_oarchive<Archive>::operator&(const T&) [with T = std::unique_ptr<Car>; Archive = boost::archive::binary_oarchive]’
    virt_funk_seri.cpp:173:14:   required from here
    /usr/include/boost/serialization/access.hpp:116:11: error: ‘class std::unique_ptr<Car>’ has no member named ‘serialize’
             t.serialize(ar, file_version);
             ~~^~~~~~~~~
    /usr/include/boost/serialization/access.hpp: In instantiation of ‘static void boost::serialization::access::serialize(Archive&, T&, unsigned int) [with Archive = boost::archive::binary_iarchive; T = std::unique_ptr<Car>]’:
    /usr/include/boost/serialization/serialization.hpp:68:22:   required from ‘void boost::serialization::serialize(Archive&, T&, unsigned int) [with Archive = boost::archive::binary_iarchive; T = std::unique_ptr<Car>]’
    /usr/include/boost/serialization/serialization.hpp:126:14:   required from ‘void boost::serialization::serialize_adl(Archive&, T&, unsigned int) [with Archive = boost::archive::binary_iarchive; T = std::unique_ptr<Car>]’
    /usr/include/boost/archive/detail/iserializer.hpp:188:40:   required from ‘void boost::archive::detail::iserializer<Archive, T>::load_object_data(boost::archive::detail::basic_iarchive&, void*, unsigned int) const [with Archive = boost::archive::binary_iarchive; T = std::unique_ptr<Car>]’
    /usr/include/boost/archive/detail/iserializer.hpp:120:1:   required from ‘class boost::archive::detail::iserializer<boost::archive::binary_iarchive, std::unique_ptr<Car> >’
    /usr/include/boost/archive/detail/iserializer.hpp:410:13:   required from ‘static void boost::archive::detail::load_non_pointer_type<Archive>::load_standard::invoke(Archive&, const T&) [with T = std::unique_ptr<Car>; Archive = boost::archive::binary_iarchive]’
    /usr/include/boost/archive/detail/iserializer.hpp:462:22:   [ skipping 2 instantiation contexts, use -ftemplate-backtrace-limit=0 to disable ]
    /usr/include/boost/archive/detail/common_iarchive.hpp:66:22:   required from ‘void boost::archive::detail::common_iarchive<Archive>::load_override(T&) [with T = std::unique_ptr<Car>; Archive = boost::archive::binary_iarchive]’
    /usr/include/boost/archive/basic_binary_iarchive.hpp:75:7:   required from ‘void boost::archive::basic_binary_iarchive<Archive>::load_override(T&) [with T = std::unique_ptr<Car>; Archive = boost::archive::binary_iarchive]’
    /usr/include/boost/archive/binary_iarchive_impl.hpp:58:9:   required from ‘void boost::archive::binary_iarchive_impl<Archive, Elem, Tr>::load_override(T&) [with T = std::unique_ptr<Car>; Archive = boost::archive::binary_iarchive; Elem = char; Tr = std::char_traits<char>]’
    /usr/include/boost/archive/detail/interface_iarchive.hpp:68:9:   required from ‘Archive& boost::archive::detail::interface_iarchive<Archive>::operator>>(T&) [with T = std::unique_ptr<Car>; Archive = boost::archive::binary_iarchive]’
    /usr/include/boost/archive/detail/interface_iarchive.hpp:75:32:   required from ‘Archive& boost::archive::detail::interface_iarchive<Archive>::operator&(T&) [with T = std::unique_ptr<Car>; Archive = boost::archive::binary_iarchive]’
    virt_funk_seri.cpp:183:14:   required from here
    /usr/include/boost/serialization/access.hpp:116:11: error: ‘class std::unique_ptr<Car>’ has no member named ‘serialize’
    
    

    Danke im Voraus.



  • Funktioniert denn die Variante ohne Zeiger (bzw. std::unique_ptr)?

    Und du mußt wohl <boost/serialization/unique_ptr.hpp> einbinden, s.a. die Antwort(en) in boost serialization std::unique_ptr support (bzw. auf eine neuere Boost-Version wechseln, falls der Header noch nicht vorhanden ist).

    Vllt. solltest du auch lernen, die Internet-Suche zu benutzen? Dafür, daß ich Boost-Serialisation noch niemals benutzt habe, ...



  • Was ist genau der Weg ohne Zeiger? Ich habe das nicht komplett verstanden.

            std::unique_ptr<Car> audi = std::make_unique<Audi>("Wilma", 3, "Rene", "Argentina" ,arma::randu<arma::mat>(4,5));
    

    sollte was genau sein?





  • Ja aber es müsste als Car definiert sein um die gleiche API zu verwenden. Ich habe früher so ausprobiert:

            std::unique_ptr<Audi> audi(new Audi);
    

    und es hat geklappt. Allerdings brauche ich das am Ende nicht.



  • Also am Ende bräuchte ich

           std::unique_ptr<Car> audi(new Audi);
           audi->getInfo();
           audi->A = arma::randu<arma::mat>(4,5);
           audi->hp = 3;
    

    und dafür braucht man dann virtuelle Funktionen in Car.



  • @mika000
    Probier mal

    #include <boost/serialization/unique_ptr.hpp>
    

    Ansonsten...
    Hier ein funktionierendes Beispielprogramm:

    #include <boost/archive/binary_oarchive.hpp>
    #include <boost/archive/binary_iarchive.hpp>
    #include <boost/serialization/assume_abstract.hpp>
    #include <boost/serialization/export.hpp>
    #include <boost/serialization/unique_ptr.hpp> // unique_ptr support
    #include <memory>
    #include <sstream>
    #include <iostream>
    
    class FooBase {
    public:
        virtual ~FooBase() = default;
        virtual char const* type() const = 0;
        virtual int get() const = 0;
        virtual void increment() = 0;
    
    private:
        friend class boost::serialization::access;
        template<class A>
        void serialize(A& ar, const unsigned int version) {
        }
    };
    
    class Foo : public FooBase {
    public:
        Foo() :i{ 100 } {}
    
        char const* type() const override { return "Foo"; }
        int get() const override { return i; }
        void increment() override { i++; }
    
    private:
        int i;
    
        friend class boost::serialization::access;
        template<class A>
        void serialize(A& ar, const unsigned int version) {
            // müssen wir aufrufen, obwohl die basisklasse leer ist.
            // die funktion wird benötigt damit Boost.Serialization die klassenhierarchie versteht und beim (de)serialisieren richtig casten kann
            ar& boost::serialization::base_object<FooBase>(*this);
            ar& i;
        }
    };
    
    class NullFoo : public FooBase {
    public:
        char const* type() const override { return "NullFoo"; }
        int get() const override { return 0; }
        void increment() override {}
    
    private:
        friend class boost::serialization::access;
        template<class A>
        void serialize(A& ar, const unsigned int version) {
            // müssen wir aufrufen, obwohl die basisklasse leer ist.
            // die funktion wird benötigt damit Boost.Serialization die klassenhierarchie versteht und beim (de)serialisieren richtig casten kann
            ar& boost::serialization::base_object<FooBase>(*this);
        }
    };
    
    BOOST_SERIALIZATION_ASSUME_ABSTRACT(FooBase);
    BOOST_CLASS_EXPORT(Foo);
    BOOST_CLASS_EXPORT(NullFoo);
    
    int main() {
        std::string str;
        {
            std::unique_ptr<FooBase> of1 = std::make_unique<Foo>();
            of1->increment();
            of1->increment();
            of1->increment();
            std::unique_ptr<FooBase> of2 = std::make_unique<NullFoo>();
            std::cout << of1->type() << ": " << of1->get() << std::endl;
            std::cout << of2->type() << ": " << of2->get() << std::endl;
    
            std::stringstream strs;
            boost::archive::binary_oarchive ar(strs);
            ar& of1;
            ar& of2;
    
            str = strs.str();
        }
        {
            std::unique_ptr<FooBase> lf1;
            std::unique_ptr<FooBase> lf2;
    
            std::stringstream strs(str);
            boost::archive::binary_iarchive ar(strs);
            ar& lf1;
            ar& lf2;
    
            std::cout << lf1->type() << ": " << lf1->get() << std::endl;
            std::cout << lf2->type() << ": " << lf2->get() << std::endl;
        }
    }
    

    Ich hab deinen Code jetzt nicht genau durchgeschaut ob da ausser dem include noch etwas fehlt/falsch ist - das kannst du aber anhand dieses funktionierenden Beispiels auch selbst machen.



  • Dein Code kann aber gar nicht so funktionieren, denn bisher hast du nur getInfo() als virtuelle Funktion in der Basisklasse Car (und für die beiden anderen Member bräuchtest du eine Audi-Variable - bzw. einen passenden Cast)...

    Hast du denn jetzt mal #include <boost/serialization/unique_ptr.hpp> ausprobiert?



  • Vielen vielen Dank @hustbaer. Ich gehe gerade durch deinen Code.

    Ja @Th69 ich habe

    #include <boost/serialization/unique_ptr.hpp>
    

    ausprobiert. Hat leider nichts geändert. Kannst du darlegen, was du mit getInfo() meinst? Hier ist der Code, den ich vorher meinte anstatt:

           std::unique_ptr<Car> audi(new Audi);
    

    gibt es

           std::unique_ptr<Audi> audi(new Audi);
    

    und da hat alles mit getInfo() geklappt:

    #include <armadillo>
    
    #include <boost/archive/binary_iarchive.hpp>
    #include <boost/archive/binary_oarchive.hpp>
    #include <boost/serialization/assume_abstract.hpp>
    #include <boost/serialization/serialization.hpp>
    #include <boost/serialization/split_member.hpp>
    
    #include <fstream>
    #include <iostream>
    #include <memory>
    #include <sstream>
    #include <vector>
    
    BOOST_SERIALIZATION_ASSUME_ABSTRACT(Car); //Tell Boost that Car is abstract
    
    //Serialization for Armadillo Matrices------------------
    BOOST_SERIALIZATION_SPLIT_FREE(arma::mat)
    namespace boost::serialization {
        template<class Archive>
        void save(Archive & ar, const arma::mat &t, unsigned int version) {
            ar << t.n_elem;
            auto data = t.colptr(0);
            for (size_t K = 0; K < t.n_elem; ++K)
                ar << data[K];
        }
    
        template<class Archive>
        void load(Archive & ar, arma::mat &t, unsigned int version) {
            size_t n_elem;
            ar >> n_elem;
            t.set_size(n_elem);
            t.zeros();
            auto data = t.colptr(0);
            for (size_t K = 0; K < n_elem; ++K)
                ar >> data[K];
        }
    } // boost::serialization
    
    class Car {
    public:
          virtual double getInfo() = 0;
    
    private:
    //    template <typename Archive>
    //    virtual void serialize(Archive& ar, unsigned int version) = 0;
    };
    
    class Porsche : public Car {
    public:
        double getInfo() override { return 1.1; }
    
        template <typename Archive>
        void serialize(Archive& ar, unsigned int) {
            ar & owner;
            ar & hp;
            ar & A;
        }
    
    public:
        std::string owner;
        int hp{};
        arma::mat A;
    };
    
    class Audi : public Car {
    public:
        double getInfo() override { return 2; }
    
        template <typename Archive>
        void serialize(Archive& ar, unsigned int) {
            ar & owner;
            ar & hp;
            ar & second_owner;
            ar & country;
            ar & A;
        }
    
    public:
        std::string owner;
        int hp{};
        std::string second_owner;
        std::string country;
     arma::mat A;
    };
    
    int main() {
        {
            std::unique_ptr<Audi> audi(new Audi);
            audi->getInfo();
            audi->A = arma::randu<arma::mat>(4,5);
            audi->hp = 3;
    
            std::unique_ptr<Porsche> porsche(new Porsche);
            porsche->getInfo();
            porsche->A = arma::randu<arma::mat>(6,5);
            porsche->hp = 14;
            porsche->owner = "Joe";
    
            std::ofstream outputStream("bin.dat", std::ios::binary);
    //      boost::archive::text_oarchive ss(outputStream);
            boost::archive::binary_oarchive ss(outputStream);
            ss & *audi.get();
            ss & *porsche.get();
        }
    
        {
            std::unique_ptr<Audi> audi(new Audi);
            std::unique_ptr<Porsche>porsche(new Porsche);
    
            std::ifstream inputStream("bin.dat", std::ios::binary);
    //      boost::archive::text_oarchive ss(outputStream);
            boost::archive::binary_iarchive ss(inputStream);
            ss & *audi.get();
            ss & *porsche.get();
    
            std::cout << "audi: hp=" << audi->hp << "\n";
            std::cout << "porsche: hp=" << porsche->hp << " owner=" << porsche->owner << " A=" << porsche-> A <<"\n";
    
        }
    }
    


  • Dieser Beitrag wurde gelöscht!


  • @mika000
    Ich glaube schön langsam das Problem ist dass du quasi keinen Plan hast davon was du da tust/versuchst zu tun.
    Lern C++.

    Konkret zu deiner Frage: Natürlich kannst du über einen Car-Zeiger nicht auf "hp" zugreifen, da Car kein Member "hp" hat. Wie soll das gehen?
    D.h. du wirst deine Car-Klasse erweitern müssen. Sieh dir mein Beispiel an, da sind die Grundzüge enthalten.



  • Genau das habe ich auch mit meinem letzten Beitrag gemeint...



  • @hustbaer das Problem ist eher, dass ich alles ausprobiert habe und es immer noch nicht funktioniert. Der Fehler "input stream error" ist jetzt weg mit Hilfe deines Codes. Aber jetzt taucht den Fehler

    terminate called after throwing an instance of 'std::bad_alloc'
      what():  std::bad_alloc
    

    auf und ich habe vesucht, den Memoryleak Fehler zu finden.

    ich habe in int main() den Code so geändert und ich bekomme den obigen Fehler:

    int main() {
        std::string str;
       {
            std::unique_ptr<Car> audi = std::make_unique<Audi>("Wilma", 3, "Rene", "Argentina" ,arma::randu<arma::mat>(4,5));
    
            std::unique_ptr<Car> porsche = std::make_unique<Porsche>("Joe", 14, arma::randu<arma::mat>(6,5));
    
            std::stringstream strs;
            boost::archive::binary_oarchive ar(strs);
            ar& audi;
            ar& porsche;
    
            str = strs.str();
        }
    
        {
            std::unique_ptr<Audi> audi = std::make_unique<Audi>();
            std::unique_ptr<Porsche>porsche = std::make_unique<Porsche>();
    
    
            std::stringstream strs(str);
            boost::archive::binary_iarchive ar(strs);
            ar& audi;
            ar& porsche;
    
            std::cout << "audi: hp=" << audi->hp << "\n";
            std::cout << "porsche: hp=" << porsche->hp<< " owner=" << porsche->owner << " A=" << porsche->A <<"\n";
    
        }
        
    }
    


  • Ich habe den Fehler debuggert und es hat mit Linie 22 in int main() zu tun:

            boost::archive::binary_iarchive ar(strs);
    
    int main() {
        std::string str;
       {
            std::unique_ptr<Car> audi = std::make_unique<Audi>("Wilma", 3, "Rene", "Argentina" ,arma::randu<arma::mat>(4,5));
    
            std::unique_ptr<Car> porsche = std::make_unique<Porsche>("Joe", 14, arma::randu<arma::mat>(6,5));
    
            std::stringstream strs;
            boost::archive::binary_oarchive ar(strs);
            ar& audi;
            ar& porsche;
    
            str = strs.str();
        }
    
        {
            std::unique_ptr<Audi> audi = std::make_unique<Audi>();
            std::unique_ptr<Porsche>porsche = std::make_unique<Porsche>();
    
    
            std::stringstream strs(str);
            boost::archive::binary_iarchive ar(strs);
            ar& audi;
            ar& porsche;
    
            std::cout << "audi: hp=" << audi->hp << "\n";
            std::cout << "porsche: hp=" << porsche->hp<< " owner=" << porsche->owner << " A=" << porsche->A <<"\n";
    
        }
        
    }
    

    Also es gibt ein Problem mit dem Laden. Hat jemand eine Idee was das Problem sein könnte? Ich habe den Code ohne das Laden (also von Linie 16 bis 29 auskommentiert) kompeliert und der Code hat ohne Fehler kompeliert.

    Der gesamte Code:

    #include <armadillo>
    
    #include <boost/archive/binary_iarchive.hpp>
    #include <boost/archive/binary_oarchive.hpp>
    #include <boost/serialization/assume_abstract.hpp>
    #include <boost/serialization/serialization.hpp>
    #include <boost/serialization/split_member.hpp>
    #include <boost/serialization/export.hpp>
    #include <boost/serialization/unique_ptr.hpp>
    
    #include <fstream>
    #include <iostream>
    #include <memory>
    #include <sstream>
    #include <vector>
    
    //Serialization for Armadillo Matrices------------------
    BOOST_SERIALIZATION_SPLIT_FREE(arma::mat)
    namespace boost::serialization {
        template<class Archive>
        void save(Archive & ar, const arma::mat &t, unsigned int version) {
            ar << t.n_elem;
            auto data = t.colptr(0);
            for (size_t K = 0; K < t.n_elem; ++K)
                ar << data[K];
        }
    
        template<class Archive>
        void load(Archive & ar, arma::mat &t, unsigned int version) {
            size_t n_elem;
            ar >> n_elem;
            t.set_size(n_elem);
            t.zeros();
            auto data = t.colptr(0);
            for (size_t K = 0; K < n_elem; ++K)
                ar >> data[K];
        }
    } // boost::serialization
    
    class Car {
    public:
        //Car() = default;
        //virtual double getInfo() = 0;
        virtual char const* type() const = 0;
        virtual ~Car() = default;
    
    private:
        friend class boost::serialization::access;
        template <class Archive>
        void serialize(Archive& ar, const unsigned int version) {};
    };
    
    class Porsche : public Car {
    public:
        char const* type() const override { return "Porsche"; }
        //double getInfo() override { return 1.1; }
        Porsche(std::string owner1, int hp1, arma::mat A1)
            {
            owner = owner1;
            hp = hp1;
            A = A1; 
    
            }
        std::string owner;
        int hp{};
        arma::mat A;
        Porsche() = default;
    private:
        friend class boost::serialization::access;
        template <class Archive>
        void serialize(Archive& ar, const unsigned int version) {
            ar & boost::serialization::base_object<Car>(*this); //https://theboostcpplibraries.com/boost.serialization-class-hierarchies
            ar & owner;
            ar & hp;
            ar & A;
        }    
    
        
    };
    
    class Audi : public Car {
    public:
        char const* type() const override { return "Audi"; }
        //double getInfo() override { return 2.2; }
        Audi(std::string owner1, int hp1, std::string second_owner1, std::string country1,  arma::mat A1)
            {
            owner = owner1;
            hp = hp1;
            second_owner = second_owner1; 
            country = country1;
            A = A1; 
            }
        Audi() = default;
    
        std::string owner;
        int hp{};
        std::string second_owner;
        std::string country;
        arma::mat A;
    
    private:
        friend class boost::serialization::access;
        template <class Archive>
        void serialize(Archive& ar, const unsigned int version) {
            ar & boost::serialization::base_object<Car>(*this); //https://theboostcpplibraries.com/boost.serialization-class-hierarchies
            ar & owner;
            ar & hp;
            ar & second_owner;
            ar & country;
            ar & A;
        }
    
    };
    
    BOOST_CLASS_EXPORT(Audi);
    BOOST_CLASS_EXPORT(Porsche);
    BOOST_SERIALIZATION_ASSUME_ABSTRACT(Car); //Tell Boost that Car is abstract
    
    
    
    int main() {
        std::string str;
       {
            std::unique_ptr<Car> audi = std::make_unique<Audi>("Wilma", 3, "Rene", "Argentina" ,arma::randu<arma::mat>(4,5));
    
            std::unique_ptr<Car> porsche = std::make_unique<Porsche>("Joe", 14, arma::randu<arma::mat>(6,5));
    
            std::stringstream strs;
            boost::archive::binary_oarchive ar(strs);
            ar& audi;
            ar& porsche;
    
            str = strs.str();
        }
    
        {
            std::unique_ptr<Audi> audi = std::make_unique<Audi>();
            std::unique_ptr<Porsche>porsche = std::make_unique<Porsche>();
    
            std::stringstream strs(str);
            boost::archive::binary_iarchive ar(strs);
            ar& audi;
            ar& porsche;
    
            std::cout << "audi: hp=" << audi->hp << "\n";
            std::cout << "porsche: hp=" << porsche->hp<< " owner=" << porsche->owner << " A=" << porsche->A <<"\n";
    
        }
        
    }
    
    


  • Funktioniert bei dir das Beispiel von folgender Seite bezüglich binary archive:

    https://kezunlin.me/post/6887a6ee/

    #include <boost/archive/binary_iarchive.hpp> 
    #include <boost/archive/binary_oarchive.hpp> 
    #include <iostream> 
    #include <sstream>
    
    class Camera {
    
    public:
        int id;
        std::string name;
        double pos;
    };
    
    namespace boost {
        namespace serialization {
    
            template<class Archive>
            void serialize(Archive& archive, Camera& cam, const unsigned int version)
            {
                archive & BOOST_SERIALIZATION_NVP(cam.id);
                archive & BOOST_SERIALIZATION_NVP(cam.name);
                archive & BOOST_SERIALIZATION_NVP(cam.pos);
            }
    
        } // namespace serialization
    } // namespace boost
    
    std::ostream& operator<<(std::ostream& cout, const Camera& cam)
    {
        cout << cam.id << std::endl
            << cam.name << std::endl
            << cam.pos << std::endl;
        return cout;
    }
    
    void save_load_with_binary_archive()
    {
        // binary archive with stringstream
        std::ostringstream oss;
        boost::archive::binary_oarchive oa(oss);
    
        Camera cam;
        cam.id = 100;
        cam.name = "new camera";
        cam.pos = 99.88;
    
        oa & (cam);
    
        // get binary content
        std::string str_data = oss.str();
        std::istringstream iss(str_data);
        boost::archive::binary_iarchive ia(iss);
        Camera new_cam;
        ia & (new_cam);
        std::cout << new_cam << std::endl;
    }
    
    int main(int argc, char** argv)
    {
        save_load_with_binary_archive();
        return 0;
    }
    


  • @firefly ja das Beispiel funktioniert. Ich bekomme:

    100
    new camera
    99.88
    
    


  • Hab wohl das Problem gefunden. Wenn eine klasse via ihrem base ptr serialisiert wird, dann muss es beim de-serialize auch über den base ptr laufen.
    Funktioniert:

    std::unique_ptr<Camera> cam = std::make_unique<Camera>();
    std::unique_ptr<Camera> cam2 = std::make_unique<MyCam>(2000);
    boost::archive::binary_oarchive oa;
    
    oa & (cam);
    oa & (cam2);
    
    boost::archive::binary_iarchive ia(iss);
    std::unique_ptr<Camera> new_cam;
    ia & (new_cam);
    
    std::unique_ptr<Camera> new_cam2;
    ia & (new_cam2);
    
    

    Funktioniert nicht:

    std::unique_ptr<Camera> cam = std::make_unique<Camera>();
    std::unique_ptr<Camera> cam2 = std::make_unique<MyCam>(2000);
    boost::archive::binary_oarchive oa;
    
    oa & (cam);
    oa & (cam2);
    
    boost::archive::binary_iarchive ia(iss);
    std::unique_ptr<Camera> new_cam;
    ia & (new_cam);
    
    std::unique_ptr<MyCam> new_cam2;
    ia & (new_cam2);
    // new_cam2 holds still an nullptr
    

    Liegt wohl daran, dass im archive die information enthalten ist wie das objekt gespeichert wurde.
    Im obigen beispiel wurde wohl die information vermerkt dass die MyCam instanz als std::unique_ptr<Camera> gespeichert wurde.
    Aber beim de-serialize wurde ein std::unique_ptr<MyCam> übergeben was so nicht der information entspricht die im archive enthalten ist. Wodurch nichts serialisiert wird.

    Und hier das vollständige Beispiel mit den verschiedenen varianten:

    #include <boost/archive/binary_iarchive.hpp> 
    #include <boost/archive/binary_oarchive.hpp>
    #include <boost/serialization/export.hpp>
    #include <boost/serialization/unique_ptr.hpp>
    #include <iostream> 
    #include <sstream>
    
    class Camera {
    
    public:
        virtual ~Camera() = default;
        int id = -1;
        std::string name="<unknown>";
        double pos = -2.0;
    };
    
    class MyCam : public Camera
    {
    public:
        MyCam(int t): bla(t){}
        MyCam() = default;
        virtual ~MyCam() = default;
        int bla;
    };
    
    namespace boost {
        namespace serialization {
    
            template<class Archive>
            void serialize(Archive& archive, Camera& cam, const unsigned int version)
            {
                archive & BOOST_SERIALIZATION_NVP(cam.id);
                archive & BOOST_SERIALIZATION_NVP(cam.name);
                archive & BOOST_SERIALIZATION_NVP(cam.pos);
            }
    
            template<class Archive>
            void serialize(Archive& archive, MyCam& cam, const unsigned int version)
            {
                archive & boost::serialization::base_object<Camera>(cam);
                archive & BOOST_SERIALIZATION_NVP(cam.bla);
            }
    
        } // namespace serialization
    } // namespace boost
    
    BOOST_CLASS_EXPORT(Camera);
    BOOST_CLASS_EXPORT(MyCam);
    
    std::ostream& operator<<(std::ostream& cout, const Camera& cam)
    {
        cout << cam.id << std::endl
            << cam.name << std::endl
            << cam.pos;
        return cout;
    }
    
    std::ostream& operator<<(std::ostream& cout, const MyCam& cam)
    {
        cout << static_cast<const Camera&>(cam) << std::endl
            << cam.bla;
        return cout;
    }
    
    void save_load_with_binary_archive()
    {
        // binary archive with stringstream
        std::ostringstream oss;
        boost::archive::binary_oarchive oa(oss);
    
        Camera cam;
        cam.id = 100;
        cam.name = "new camera";
        cam.pos = 99.88;
    
        oa & (cam);
    
        // get binary content
        std::string str_data = oss.str();
        std::istringstream iss(str_data);
        boost::archive::binary_iarchive ia(iss);
        Camera new_cam;
        ia & (new_cam);
        std::cout << new_cam <<'\n'<< std::endl;
    }
    
    void save_load_with_binary_archive_unique_ptr()
    {
        // binary archive with stringstream
        std::ostringstream oss;
        boost::archive::binary_oarchive oa(oss);
    
        std::unique_ptr<Camera> cam = std::make_unique<Camera>();
        cam->id = 200;
        cam->name = "new camera";
        cam->pos = 99.88;
    
        oa & (cam);
        
        std::unique_ptr<MyCam> cam2 = std::make_unique<MyCam>(1000);
        cam2->id = 300;
        cam2->name = "my camera";
        cam2->pos = 42.2;
        
        oa & (cam2);
    
        // get binary content
        std::string str_data = oss.str();
        std::istringstream iss(str_data);
        boost::archive::binary_iarchive ia(iss);
        std::unique_ptr<Camera> new_cam;
        ia & (new_cam);
        std::cout << *(new_cam.get()) <<'\n' << std::endl;
        
        std::unique_ptr<MyCam> new_cam2;
        ia & (new_cam2);
        std::cout << *(new_cam2.get()) <<'\n' << std::endl;
    }
    
    void save_load_with_binary_archive_unique_ptr_base()
    {
        // Serialize child class via base class and deserialize via base class
        // binary archive with stringstream
        std::ostringstream oss;
        boost::archive::binary_oarchive oa(oss);
    
        std::unique_ptr<Camera> cam = std::make_unique<Camera>();
        cam->id = 2002;
        cam->name = "new camera2";
        cam->pos = 99.88;
    
        oa & (cam);
        
        std::unique_ptr<Camera> cam2 = std::make_unique<MyCam>(2000);
        cam2->id = 3002;
        cam2->name = "my camera2";
        cam2->pos = 42.2;
        
        oa & (cam2);
    
        // get binary content
        std::string str_data = oss.str();
        std::istringstream iss(str_data);
        boost::archive::binary_iarchive ia(iss);
        std::unique_ptr<Camera> new_cam;
        ia & (new_cam);
        std::cout << *(new_cam.get()) <<'\n' << std::endl;
        
        std::unique_ptr<Camera> new_cam2;
        ia & (new_cam2);
        std::cout << *static_cast<MyCam*>(new_cam2.get()) <<'\n' << std::endl;
    }
    
    void save_load_with_binary_archive_unique_ptr_notbase()
    {
        // Serialize child class via base class but deserialize via child class
        // binary archive with stringstream
        std::ostringstream oss;
        boost::archive::binary_oarchive oa(oss);
    
        std::unique_ptr<Camera> cam = std::make_unique<Camera>();
        cam->id = 2002;
        cam->name = "new camera2";
        cam->pos = 99.88;
    
        oa & (cam);
        
        std::unique_ptr<Camera> cam2 = std::make_unique<MyCam>(2000);
        cam2->id = 3002;
        cam2->name = "my camera2";
        cam2->pos = 42.2;
        
        oa & (cam2);
    
        // get binary content
        std::string str_data = oss.str();
        std::istringstream iss(str_data);
        boost::archive::binary_iarchive ia(iss);
        std::unique_ptr<Camera> new_cam = std::make_unique<Camera>();
        ia & (new_cam);
        std::cout << *(new_cam.get()) <<'\n' << std::endl;
        
        // Create instance here because here gets nothing deserialized and thus the output code would crash
        std::unique_ptr<MyCam> new_cam2 = std::make_unique<MyCam>(-1);
        ia & (new_cam2);
        std::cout << *(new_cam2.get()) <<'\n' << std::endl;
    }
    
    int main(int argc, char** argv)
    {
        save_load_with_binary_archive();
        std::cout<<"unique_ptr:\n";
        save_load_with_binary_archive_unique_ptr();
        
        std::cout<<"unique_ptr on base:\n";
        save_load_with_binary_archive_unique_ptr_base();
        
        std::cout<<"unique_ptr not base:\n";
        save_load_with_binary_archive_unique_ptr_notbase();
        return 0;
    }
    
    

Anmelden zum Antworten