Pengenalan shared_ptr menyebabkan kesalahan segmentasi saat deserialisasi (dengan boost::serialisasi)

Saya memiliki gamma kelas, seperti yang ditunjukkan di bawah ini.

Fungsi load menimbulkan kesalahan segmentasi, ketika fungsi make_nvp mencoba melakukan deserialisasi file xml yang ada. Kesalahan muncul ketika saya menggunakan std::shared_ptr<std::tuple<double,double,double>> val;

Jika sebaliknya val hanya std::tuple<double,double,double> val;

kemudian semuanya tampak berfungsi dengan baik (Tentu saja, saya mengubah fungsi pengambil dan penyetel sesuai).

Sekarang saya membahas banyak pertanyaan tentang stackoverflow dan saya mencari di Google dan melihat contoh di dokumentasi boost dan saya tidak tahu, mengapa fungsi load menyebabkan program dihentikan dengan kesalahan segmentasi.

Catatan: Beberapa postingan lama di internet (dan beberapa pertanyaan lama tentang stackoverflow) tampaknya menyiratkan bahwa std::shared_ptr dulunya tidak berfungsi dengan peningkatan serialisasi pada saat itu. Saya rasa hal ini tidak terjadi pada tahun 2017. Bagaimanapun, untuk memastikan, saya mencoba mengganti std::shared_ptr dengan boost::shared_ptr dan kesalahan segmentasi masih ada.

Saya tidak mengerti/mengerti mengapa kesalahan itu muncul?

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);
    }
};

dan 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 sumber
comment
Kode Anda tidak lengkap dan tidak dapat dikompilasi sebagaimana adanya.   -  person overseas    schedule 03.03.2017
comment
Ya. Saya hanya menambahkan kelas yang menyebabkan masalah. Ini adalah bagian dari proyek yang lebih besar, di mana saya sampai di kelas ini setelah melewati rangkaian kelas lain, dimulai dari kelas utama. Coba saya lihat lagi, apakah saya bisa menambahkan kelas-kelas itu di sini dengan cara yang bersih.   -  person Duck Dodgers    schedule 06.03.2017
comment
@luar negeri, ada juga kesalahan kecil pada nama kelas dari dua fungsi terakhir, load() dan save(). Saya memperbaikinya sekarang. Pengguna sehe hanya menambahkan main() untuk memanggil kelas ini dan tampaknya dia tidak mendapatkan kesalahan segmentasi di sana. Hmm, penasaran! Mungkin kesalahan seg disebabkan oleh hal lain. Akan memeriksa dalam beberapa jam.   -  person Duck Dodgers    schedule 06.03.2017
comment
Cobalah untuk mendapatkan mcve (stackoverflow.com/help/mcve) dan kami melihat apa yang dapat kami lakukan. Kode ini tidak dapat dikompilasi (contohnya hilang) dan saya juga tidak dapat menebak masalah apa yang Anda hadapi, karena jika saya memperbaiki kesalahan yang jelas dan memberikan main sederhana saya tidak dapat mendeteksi masalah.   -  person overseas    schedule 06.03.2017


Jawaban (1)


Merupakan misteri bagi saya apa yang sebenarnya dapat ditambahkan oleh shared_ptr ke satu Tuple di dalam... satu singleton. Tapi bagaimanapun, saya membuat kode Anda mandiri dan berfungsi:

Langsung di Coliru

Saya harap Anda dapat mengetahui bagian mana yang Anda lakukan secara berbeda/salah:

#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);
    }
}

Mencetak data berikut:

<?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
Hai. Terima kasih telah mengabaikan kesalahan salin/tempel/edit saya karena lupa mengganti nama kelas untuk dua fungsi terakhir (load() dan save()) dari CalibrationDataObject ke Gamma. :D Beri saya waktu beberapa jam, dan saya akan membahasnya lagi. Dan ya. Kamu benar. Menambahkan shared_ptr sepertinya tidak menghasilkan apa-apa di sini (dan kode asli juga tidak menggunakan shared_ptr di lokasi ini) tetapi kemudian seseorang (bukan saya) mengeditnya (untuk beberapa alasan?!?) dan setelah pengujian, saya perhatikan bahwa sepertinya merusak fungsi memuat, yang membuat saya penasaran. Terima kasih atas waktunya. - person Duck Dodgers; 06.03.2017
comment
Hmm, saya juga tidak melihat kesalahan. :/ Oke. Hal ini sendiri sangat membantu. Saya menerima jawaban Anda. - person Duck Dodgers; 07.03.2017
comment
@JoeyMallone mungkin Anda memuat arsip yang disimpan dengan versi lama. Tata letaknya tidak akan kompatibel (Anda harus melakukan Pembuatan Versi Kelas jika Anda ingin memuat format arsip lama) - person sehe; 08.03.2017
comment
Kami hampir sampai pada kesimpulan yang sama. Pesan debug Boost bisa sangat samar. Hanya dengan pengalaman seseorang dapat mengetahui, apa kesalahannya, karena keluaran debug tampaknya sama sekali tidak dapat digunakan. - person Duck Dodgers; 08.03.2017