การแนะนำ shared_ptr นำไปสู่ข้อผิดพลาดในการแบ่งส่วนเมื่อทำการดีซีเรียลไลซ์ (พร้อมเพิ่ม :: การทำให้เป็นอนุกรม)

ฉันมีคลาสแกมมาดังที่แสดงด้านล่าง

ฟังก์ชันโหลดจะส่งข้อผิดพลาดในการแบ่งส่วน เมื่อฟังก์ชัน make_nvp พยายามดีซีเรียลไลซ์ไฟล์ xml ที่มีอยู่ เกิดข้อผิดพลาดเมื่อฉันใช้ std::shared_ptr<std::tuple<double,double,double>> val;

ถ้าแทน val เป็นเพียง std::tuple<double,double,double> val;

ดูเหมือนว่าทุกอย่างจะทำงานได้ดี (แน่นอน ฉันเปลี่ยนฟังก์ชัน getter และ setter ตามนั้น)

ตอนนี้ ฉันได้ถามคำถามมากมายเกี่ยวกับ stackoverflow และฉันได้ค้นหาใน Google และดูตัวอย่างในเอกสารบูสต์ และฉันไม่เข้าใจว่าทำไมฟังก์ชันโหลดจึงทำให้โปรแกรมยุติการทำงานด้วยข้อผิดพลาดในการแบ่งเซ็กเมนต์

หมายเหตุ: โพสต์เก่าๆ บางโพสต์บนอินเทอร์เน็ต (และคำถามเก่าๆ เกี่ยวกับ stackoverflow) ดูเหมือนจะบอกเป็นนัยว่า std::shared_ptr เคยใช้งานไม่ได้กับการเพิ่มอนุกรม ณ เวลานั้น ฉันไม่คิดว่าจะเป็นกรณีนี้ในปี 2560 อย่างไรก็ตาม เพื่อให้แน่ใจ ฉันได้ลองแทนที่ std::shared_ptr ด้วย boost::shared_ptr และข้อผิดพลาดในการแบ่งส่วนยังคงอยู่ที่นั่น

ฉันไม่เข้าใจ/ดูสาเหตุที่เกิดข้อผิดพลาด?

gamma.h

#pragma once
#include <map>
#include <boost/serialization/access.hpp>
#include <boost/serialization/nvp.hpp>
#include <boost/serialization/map.hpp>
#include <boost/serialization/vector.hpp>
#include <boost/serialization/utility.hpp>
#include <boost/serialization/shared_ptr.hpp>

#include <tuple>

namespace boost
{
    namespace serialization
    {
        template<typename Archive>
        void serialize(Archive & ar, std::tuple<double, double, double> & t,
                    const unsigned int version)
        {
            ar & boost::serialization::make_nvp("t0",std::get<0>(t));
            ar & boost::serialization::make_nvp("t1",std::get<1>(t));
            ar & boost::serialization::make_nvp("t2",std::get<2>(t));
        }

    }
}

class Gamma
{
public:
    static void save(std::ostream& os);
    static void load(std::istream& is);

    std::shared_ptr<std::tuple<double, double, double>> getterX() const;
    void setterX(const std::tuple<double, double, double> &val);

private:

    std::shared_ptr<std::tuple<double,double,double>> val;

    friend class boost::serialization::access;
    template<typename Archive>
    void serialize(Archive& arc, const unsigned int version)
    {
          arc & boost::serialization::make_nvp("val", val);
    }
};

และ gamma.cpp

#include "gamma.h"
#include <boost/archive/xml_iarchive.hpp>
#include <boost/archive/xml_oarchive.hpp>
#include <boost/serialization/access.hpp>
#include <boost/serialization/nvp.hpp>
#include <boost/serialization/utility.hpp>

Gamma &Gamma::instance()
{
    static Gamma obj;
    return obj;
}

std::shared_ptr<std::tuple<double, double, double>> Gamma::getterX() const
{
    return val;
}

void Gamma::setterX(const std::tuple<double, double,double> &v)
{
    if (nullptr == val) {
        m_touchDownCalibration = std::make_shared<std::tuple<double, double,double>>();
    }
    *val = v;
}

const char* TAG = "tag";

void Gamma::save(std::ostream& os)
{
    boost::archive::xml_oarchive arc(os);
    arc & boost::serialization::make_nvp(TAG,instance());
}

void Gamma::load(std::istream& is)
{
    boost::archive::xml_iarchive arc(is);
    arc & boost::serialization::make_nvp(TAG,instance());
}

person Duck Dodgers    schedule 03.03.2017    source แหล่งที่มา
comment
รหัสของคุณไม่สมบูรณ์และไม่ได้คอมไพล์ตามที่เป็นอยู่   -  person overseas    schedule 03.03.2017
comment
ใช่. ฉันเพิ่มเฉพาะคลาสที่ทำให้เกิดปัญหาเท่านั้น นี่เป็นส่วนหนึ่งของโปรเจ็กต์ที่ใหญ่กว่า ซึ่งฉันมาถึงคลาสนี้หลังจากผ่านคลาสอื่นๆ ต่อเนื่องกัน โดยเริ่มจากคลาสหลัก ให้ฉันดูอีกครั้งถ้าฉันสามารถเพิ่มคลาสเหล่านั้นที่นี่ได้อย่างสะอาดตา   -  person Duck Dodgers    schedule 06.03.2017
comment
@overseas มีข้อผิดพลาดเล็กน้อยในชื่อคลาสของสองฟังก์ชันสุดท้ายคือ load() และ save() ฉันแก้ไขสิ่งนั้นแล้ว ผู้ใช้ sehe เพิ่มเพียง main() สำหรับการเรียกคลาสนี้และดูเหมือนว่าเขาจะไม่มีข้อผิดพลาดในการแบ่งส่วนที่นั่น อืม อยากรู้! อาจเป็นเพราะข้อผิดพลาด seg เกิดจากสิ่งอื่น จะตรวจสอบภายในสองสามชั่วโมง   -  person Duck Dodgers    schedule 06.03.2017
comment
ลองรับ mcve (stackoverflow.com/help/mcve) แล้วเราจะดูว่าเราทำอะไรได้บ้าง รหัสนี้ไม่คอมไพล์ (ไม่มีอินสแตนซ์) และฉันไม่สามารถเดาได้ว่าคุณประสบปัญหาอะไร เพราะถ้าฉันแก้ไขข้อผิดพลาดที่ชัดเจนและระบุ main แบบง่าย ๆ ฉันจะตรวจไม่พบปัญหา   -  person overseas    schedule 06.03.2017


คำตอบ (1)


เป็นเรื่องลึกลับสำหรับฉันว่า shared_ptr สามารถเพิ่มลงใน tuple เดียวภายในได้อย่างไร... singleton แต่อย่างไรก็ตาม ฉันทำให้โค้ดของคุณมีอยู่ในตัวเองและใช้งานได้:

สดบน Coliru

ฉันหวังว่าคุณจะเข้าใจได้ว่าส่วนไหนที่คุณทำแตกต่าง/ผิด:

#include <map>
#include <boost/serialization/access.hpp>
#include <boost/serialization/nvp.hpp>
#include <boost/serialization/map.hpp>
#include <boost/serialization/vector.hpp>
#include <boost/serialization/utility.hpp>
#include <boost/serialization/shared_ptr.hpp>

#include <tuple>

namespace boost { namespace serialization {
    template<typename Archive>
    void serialize(Archive & ar, std::tuple<double, double, double> & t, unsigned) {
        ar & boost::serialization::make_nvp("t0", std::get<0>(t));
        ar & boost::serialization::make_nvp("t1", std::get<1>(t));
        ar & boost::serialization::make_nvp("t2", std::get<2>(t));
    }
} }

class CalibrationDataObject
{
public:
    static CalibrationDataObject &instance();
    static void save(std::ostream& os);
    static void load(std::istream& is);

    std::shared_ptr<std::tuple<double, double, double>> getterX() const;
    void setterX(const std::tuple<double, double, double> &val);

private:
    std::shared_ptr<std::tuple<double,double,double>> val;

    friend class boost::serialization::access;
    template<typename Archive>
    void serialize(Archive& arc, unsigned)
    {
          arc & boost::serialization::make_nvp("val", val);
    }
};

//#include "CalibrationDataObject.h"
#include <boost/archive/xml_iarchive.hpp>
#include <boost/archive/xml_oarchive.hpp>
#include <boost/serialization/access.hpp>
#include <boost/serialization/nvp.hpp>
#include <boost/serialization/utility.hpp>

CalibrationDataObject &CalibrationDataObject::instance() { static CalibrationDataObject obj; return obj; }

std::shared_ptr<std::tuple<double, double, double>> CalibrationDataObject::getterX() const {
    return val;
}

void CalibrationDataObject::setterX(const std::tuple<double, double,double> &v)
{
    if (val)
        *val = v;
    else 
        val = std::make_shared<std::tuple<double, double,double>>(v);
}

const char* TAG = "tag";

void CalibrationDataObject::save(std::ostream& os)
{
    boost::archive::xml_oarchive arc(os);
    arc & boost::serialization::make_nvp(TAG,instance());
}

void CalibrationDataObject::load(std::istream& is)
{
    boost::archive::xml_iarchive arc(is);
    arc & boost::serialization::make_nvp(TAG,instance());
}

#include <fstream>

int main() {
    {
        std::ofstream ofs("test.data");
        CalibrationDataObject::save(ofs);
    }
    {
        std::ifstream ifs("test.data");
        CalibrationDataObject::load(ifs);
    }
}

การพิมพ์ข้อมูลต่อไปนี้:

<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<!DOCTYPE boost_serialization>
<boost_serialization signature="serialization::archive" version="14">
<tag class_id="0" tracking_level="0" version="0">
    <val class_id="1" tracking_level="0" version="1">
        <px class_id="-1"></px>
    </val>
</tag>
</boost_serialization>
person sehe    schedule 03.03.2017
comment
สวัสดี. ขอขอบคุณที่มองข้ามข้อผิดพลาดในการคัดลอก/วาง/แก้ไขของฉันในการลืมเปลี่ยนชื่อคลาสสำหรับสองฟังก์ชันสุดท้าย (load() และ save()) จาก CalibrationDataObject เป็น Gamma :D ให้เวลาฉันสองสามชั่วโมงแล้วฉันจะทำซ้ำอีกครั้ง และใช่. คุณพูดถูก การเพิ่ม shared_ptr ดูเหมือนจะไม่ประสบผลสำเร็จที่นี่ (และโค้ดต้นฉบับก็ไม่ได้ใช้ shared_ptr ที่ตำแหน่งนี้) แต่แล้วก็มีใครบางคน (ไม่ใช่ฉัน) แก้ไขมัน (ด้วยเหตุผลบางอย่าง?!?) และเมื่อทำการทดสอบ ฉันสังเกตเห็นว่าดูเหมือนว่าจะ ทำลายฟังก์ชันโหลดซึ่งทำให้ฉันอยากรู้ ขอบคุณที่สละเวลา. - person Duck Dodgers; 06.03.2017
comment
อืม ฉันก็ไม่เห็นข้อผิดพลาดเช่นกัน :/ ตกลง. สิ่งนี้มีประโยชน์ในตัวมันเอง ฉันยอมรับคำตอบของคุณ - person Duck Dodgers; 07.03.2017
comment
@JoeyMallone บางทีคุณอาจกำลังโหลดไฟล์เก็บถาวรที่บันทึกไว้ในเวอร์ชันเก่า เค้าโครงจะไม่เข้ากัน (คุณต้องทำ การกำหนดเวอร์ชันของคลาส หากคุณต้องการโหลดรูปแบบไฟล์เก็บถาวรเก่า) - person sehe; 08.03.2017
comment
เราเกือบจะได้ข้อสรุปเดียวกัน ข้อความแก้ไขข้อบกพร่องของ Boost อาจเป็นความลับมาก มีเพียงผู้มีประสบการณ์เท่านั้นที่จะสามารถบอกได้ว่าข้อผิดพลาดคืออะไร เพราะผลลัพธ์ของการดีบักดูเหมือนจะใช้ไม่ได้โดยสิ้นเชิง - person Duck Dodgers; 08.03.2017