【问题标题】:how to deserialize and get member value using boost library如何使用 boost 库反序列化和获取成员值
【发布时间】:2021-02-02 09:32:36
【问题描述】:

首先,我想告诉你

  1. 我是序列化技术的新手
  2. 我对使用 boost 序列化并不是完全空白,但我所经历的大多数示例都非常直接(例如,只有一个类,最多一个基类和一个派生类)。

我以here 为例。在这里,代码作者通过使用类bus_schedule 使用了saveload 函数。在此处调用的对象new_schedule 的帮助下,我遇到了获取所有成员变量的问题。我假设,这个对象将帮助我获取其他类的所有成员(也许我在这一点上完全错了)。

除此之外,我已经看到,大部分成员变量都在这里private,这意味着我无法从main 函数访问它们。这就是为什么,我设置了一些 getter 函数来返回一些成员值。例如,从bus_schedule 类中,如果我可以返回schedule 列表,那么我可以访问trip_info 结构值以及类型为bus_route 的指针。

我用过的返回schedule列表的函数是:

std::list<std::pair<trip_info, bus_route *> >  return_schedule()
     {
         return schedule;
     }

在我使用过的main函数中:

bus_schedule new_schedule;
auto returning_schedule = new_schedule.return_schedule();
for(auto i:returning_schedule)
    {
        cout<<(i.first)<<" ~~~~~~~ "<<(i.second)<<endl;
       /*with i.first I can access the struct info, i.second pointer gives me the info of
       bus_route pointer value ater dereferencing*/
    }

但在这里,我再次坚持从 i.second 指针获取单独的值。我知道,bus_route 类有一个名为stops 的列表。 Here 也返回了这个。但在我看来,每次进行这种反算都很麻烦。

我的问题是,boost 是否有任何直接解决方案可以在反序列化后访问所有成员变量?我将为所有班级设置 getter 函数,但害怕找到使用这些函数的途径。

【问题讨论】:

    标签: c++ serialization boost deserialization


    【解决方案1】:

    这个问题实际上与序列化是分开的。这是没有序列化内容的数据结构。我对代码进行了现代化改造以使用 C++17 功能

    • auto 和移动语义
    • defaulted 特别会员
    • [[nodiscard]], override 关键字
    • 显式构造函数和emplace
    • 带解构的ranged-for循环
    • make_unique&lt;&gt; 而不是 new/delete
    • 扩展聚合初始化器

    总而言之,它使代码更短、更简单、更高效¹。此外,它突出显示了您想知道的一些事情,我将在下面展示。

    Live On Coliru

    #include <iostream>
    #include <list>
    #include <memory>
    #include <string>
    
    struct gps_position {
        int degrees;
        int minutes;
        float seconds;
    
        friend std::ostream& operator<<(std::ostream& os, const gps_position& gp) {
            return os << ' ' << gp.degrees << "º" << gp.minutes << "'" << gp.seconds << '"';
        }
    };
    
    /////////////////////////////////////////////////////////////
    // One bus stop
    struct bus_stop {
        gps_position latitude, longitude;
    
        [[nodiscard]] virtual std::string description() const = 0;
        virtual ~bus_stop() = default;
        friend std::ostream& operator<<(std::ostream& os, const bus_stop& bs) {
            return os << bs.latitude << bs.longitude << ' ' << bs.description();
        }
    
      protected:
        explicit bus_stop(gps_position _lat, gps_position _long)
                : latitude(_lat), longitude(_long) {}
    };
    
    /////////////////////////////////////////////////////////////
    // Several kinds of bus stops
    struct bus_stop_corner : bus_stop {
        std::string street1, street2;
        [[nodiscard]] std::string description() const override {
            return street1 + " and " + street2;
        }
    
        explicit bus_stop_corner(gps_position _lat, gps_position _long, std::string _s1, std::string _s2)
            : bus_stop(_lat, _long), street1(std::move(_s1)), street2(std::move(_s2)) {}
    };
    
    struct bus_stop_destination : bus_stop {
        std::string name;
        [[nodiscard]] std::string description() const override { return name; }
    
        bus_stop_destination(gps_position _lat, gps_position _long, std::string _name)
            : bus_stop(_lat, _long), name(std::move(_name)) {}
    };
    
    struct bus_route {
        using bus_stop_pointer = bus_stop*;
        std::list<bus_stop_pointer> stops;
    
        void append(bus_stop* _bs) { stops.insert(stops.end(), _bs); }
        friend std::ostream& operator<<(std::ostream& os, const bus_route& br) {
            for (auto& stop : br.stops) {
                os << '\n' << std::hex << "0x" << stop << std::dec << ' ' << *stop;
            }
            return os;
        }
    };
    
    /////////////////////////////////////////////////////////////
    // a bus schedule is a collection of routes each with a starting time
    struct bus_schedule {
        struct trip_info { int hour, minute; std::string driver; };
    
        void append(const std::string& _d, int _h, int _m, bus_route* _br) {
            schedule.emplace(schedule.end(), trip_info{_h, _m, _d}, _br);
        }
    
      private:
        friend std::ostream& operator<<(std::ostream& os, const bus_schedule& bs) {
            for (auto const& [k,v] : bs.schedule) { os << k << *v; }
            return os;
        }
        friend std::ostream& operator<<(std::ostream& os, const bus_schedule::trip_info& ti) {
            return os << '\n' << ti.hour << ':' << ti.minute << ' ' << ti.driver << ' ';
        }
        std::list<std::pair<trip_info, bus_route*>> schedule;
    };
    
    int main() {
        // fill in the data
        // make a few stops
        auto bs0 = std::make_unique<bus_stop_corner>(
            gps_position{ 34, 135, 52.560F }, gps_position{ 134, 22, 78.30F },
            "24th Street", "10th Avenue");
        auto bs1 = std::make_unique<bus_stop_corner>(
            gps_position{ 35, 137, 23.456F }, gps_position{ 133, 35, 54.12F },
            "State street", "Cathedral Vista Lane");
        auto bs2 = std::make_unique<bus_stop_destination>(
            gps_position{ 35, 136, 15.456F }, gps_position{ 133, 32, 15.300F },
            "White House");
        auto bs3 = std::make_unique<bus_stop_destination>(
            gps_position{ 35, 134, 48.789F }, gps_position{ 133, 32, 16.230F },
            "Lincoln Memorial");
    
        // make the schedule
        bus_schedule original_schedule;
        bus_route route0;
    
        bus_route route1;
    
        {
            // make a route
            route0.append(bs0.get());
            route0.append(bs1.get());
            route0.append(bs2.get());
    
            // add trips to schedule
            original_schedule.append("bob",   6,  24, &route0);
            original_schedule.append("bob",   9,  57, &route0);
            original_schedule.append("alice", 11, 2,  &route0);
        }
    
        {
            // make aother routes
            route1.append(bs3.get());
            route1.append(bs2.get());
            route1.append(bs1.get());
    
            // add trips to schedule
            original_schedule.append("ted",   7,  17, &route1);
            original_schedule.append("ted",   9,  38, &route1);
            original_schedule.append("alice", 11, 47, &route1);
        }
    
        // display the complete schedule
        std::cout << "schedule" << original_schedule;
    }
    

    打印:

    schedule
    6:24 bob 
     34º135'52.56" 134º22'78.3" 24th Street and 10th Avenue
     35º137'23.456" 133º35'54.12" State street and Cathedral Vista Lane
     35º136'15.456" 133º32'15.3" White House
    9:57 bob 
     34º135'52.56" 134º22'78.3" 24th Street and 10th Avenue
     35º137'23.456" 133º35'54.12" State street and Cathedral Vista Lane
     35º136'15.456" 133º32'15.3" White House
    11:2 alice 
     34º135'52.56" 134º22'78.3" 24th Street and 10th Avenue
     35º137'23.456" 133º35'54.12" State street and Cathedral Vista Lane
     35º136'15.456" 133º32'15.3" White House
    7:17 ted 
     35º134'48.789" 133º32'16.23" Lincoln Memorial
     35º136'15.456" 133º32'15.3" White House
     35º137'23.456" 133º35'54.12" State street and Cathedral Vista Lane
    9:38 ted 
     35º134'48.789" 133º32'16.23" Lincoln Memorial
     35º136'15.456" 133º32'15.3" White House
     35º137'23.456" 133º35'54.12" State street and Cathedral Vista Lane
    11:47 alice 
     35º134'48.789" 133º32'16.23" Lincoln Memorial
     35º136'15.456" 133º32'15.3" White House
     35º137'23.456" 133º35'54.12" State street and Cathedral Vista Lane
    

    结论

    为了方便地使用 map 数据结构,您可以使用循环 as the example has it

    std::list<
        std::pair<bus_schedule::trip_info, bus_route*>>::const_iterator it;
    for (it = bs.schedule.begin(); it != bs.schedule.end(); it++) {
        os << it->first << *(it->second);
    }
    

    但是,在 C++17 中,您的编写方式与以下内容完全相同:

    for (auto const& [info,route] : bs.schedule) { os << info << *route; }
    

    您可以看到[k, v] 使用结构化绑定来提取值类型的“第一”和“第二”部分。如果您的编译器中没有 C++17 功能,您始终可以手动执行相同操作:

    for (auto const& pair : bs.schedule) {
        trip_info const& info = pair.first;
        bus_route const& route = *pair.second;
        os << info << route;
    }
    

    四处逛逛private 成员

    我认为这种数据结构不是典型的或“好的”惯用 C++。使用原始指针会导致内存管理错误(例如,反序列化路由的每一站都会泄露)。

    添加到这个“装置”getter/setter 风险putting lipstick on a pig²。

    我会选择公开您需要公开的内容。这是一个从 main 打印详细信息的示例,而不会重载 operator&lt;&lt; 运算符:

    // display the complete schedule
    std::cout << "schedule";
    for (auto const& [info,route] : original_schedule.schedule) {
        std::cout << '\n' << info.hour << ':' << info.minute << ' ' << info.driver << ' ';
        for (auto& stop : route->stops)
            std::cout << '\n' << stop->latitude << stop->longitude << ' ' << stop->description();
    }
    

    打印和以前一样。

    完整列表

    Live On Coliru

    #include <iostream>
    #include <list>
    #include <memory>
    #include <string>
    
    struct gps_position {
        int degrees;
        int minutes;
        float seconds;
    
        friend std::ostream& operator<<(std::ostream& os, const gps_position& gp) {
            return os << ' ' << gp.degrees << "º" << gp.minutes << "'" << gp.seconds << '"';
        }
    };
    
    /////////////////////////////////////////////////////////////
    // One bus stop
    struct bus_stop {
        gps_position latitude, longitude;
    
        [[nodiscard]] virtual std::string description() const = 0;
        virtual ~bus_stop() = default;
    
        explicit bus_stop(gps_position _lat, gps_position _long)
                : latitude(_lat), longitude(_long) {}
    };
    
    /////////////////////////////////////////////////////////////
    // Several kinds of bus stops
    struct bus_stop_corner : bus_stop {
        std::string street1, street2;
        [[nodiscard]] std::string description() const override {
            return street1 + " and " + street2;
        }
    
        explicit bus_stop_corner(gps_position _lat, gps_position _long, std::string _s1, std::string _s2)
            : bus_stop(_lat, _long), street1(std::move(_s1)), street2(std::move(_s2)) {}
    };
    
    struct bus_stop_destination : bus_stop {
        std::string name;
        [[nodiscard]] std::string description() const override { return name; }
    
        bus_stop_destination(gps_position _lat, gps_position _long, std::string _name)
            : bus_stop(_lat, _long), name(std::move(_name)) {}
    };
    
    struct bus_route {
        std::list<bus_stop*> stops;
        void append(bus_stop* _bs) { stops.push_back(_bs); }
    };
    
    /////////////////////////////////////////////////////////////
    // a bus schedule is a collection of routes each with a starting time
    struct bus_schedule {
        struct trip_info { int hour, minute; std::string driver; };
    
        void append(const std::string& _d, int _h, int _m, bus_route* _br) {
            schedule.emplace(schedule.end(), trip_info{_h, _m, _d}, _br);
        }
    
        std::list<std::pair<trip_info, bus_route*>> schedule;
    };
    
    int main() {
        // fill in the data
        // make a few stops
        auto bs0 = std::make_unique<bus_stop_corner>(
            gps_position{ 34, 135, 52.560F }, gps_position{ 134, 22, 78.30F },
            "24th Street", "10th Avenue");
        auto bs1 = std::make_unique<bus_stop_corner>(
            gps_position{ 35, 137, 23.456F }, gps_position{ 133, 35, 54.12F },
            "State street", "Cathedral Vista Lane");
        auto bs2 = std::make_unique<bus_stop_destination>(
            gps_position{ 35, 136, 15.456F }, gps_position{ 133, 32, 15.300F },
            "White House");
        auto bs3 = std::make_unique<bus_stop_destination>(
            gps_position{ 35, 134, 48.789F }, gps_position{ 133, 32, 16.230F },
            "Lincoln Memorial");
    
        // make the schedule
        bus_schedule original_schedule;
        bus_route route0;
    
        bus_route route1;
    
        {
            // make a route
            route0.append(bs0.get());
            route0.append(bs1.get());
            route0.append(bs2.get());
    
            // add trips to schedule
            original_schedule.append("bob",   6,  24, &route0);
            original_schedule.append("bob",   9,  57, &route0);
            original_schedule.append("alice", 11, 2,  &route0);
        }
    
        {
            // make aother routes
            route1.append(bs3.get());
            route1.append(bs2.get());
            route1.append(bs1.get());
    
            // add trips to schedule
            original_schedule.append("ted",   7,  17, &route1);
            original_schedule.append("ted",   9,  38, &route1);
            original_schedule.append("alice", 11, 47, &route1);
        }
    
        // display the complete schedule
        std::cout << "schedule";
        for (auto const& [info,route] : original_schedule.schedule) {
            std::cout << '\n' << info.hour << ':' << info.minute << ' ' << info.driver << ' ';
            for (auto& stop : route->stops)
                std::cout << '\n' << stop->latitude << stop->longitude << ' ' << stop->description();
        }
    }
    

    请注意,即使removing all blank lines and comments, and using the same formatting,代码也比示例短 100 行。


    ¹ 请注意,代码显然根本不是客观上“高效”的,因为它执行各种动态分配和运行时多态性

    ² 这种反模式对于具有传统 OOP 背景的人来说很常见,请参阅 pseudo/quasi-classes (PDF)

    【讨论】:

    猜你喜欢
    • 2013-04-08
    • 1970-01-01
    • 2012-09-05
    • 2015-01-22
    • 1970-01-01
    • 1970-01-01
    • 2013-07-15
    • 1970-01-01
    • 2019-03-05
    相关资源
    最近更新 更多