Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
81 views
in Technique[技术] by (71.8m points)

c++ - Input stream problem when using std::array

When there is no bool b in struct A, the code works. When bool b is there, ar & mat gives "input stream error" but registering elements of std::array one by one works. What's wrong here?

#include <fstream>
#include <boost/serialization/array.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>

struct A
{
    std::array<int, 3> mat;
    bool b;

    template<class Archive> void serialize(Archive& ar, const unsigned int version)
    {
        //ar & mat[0];
        //ar & mat[1];
        //ar & mat[2];
        ar & mat;
        ar & b;
    }
};


int main()
{
    {
        std::string fname = "save.sr";
        std::ofstream ofs(fname);
        boost::archive::text_oarchive oa(ofs);
        A a;
        oa << a;
    }

    {
        std::string fname = "save.sr";
        std::ifstream ifs(fname);
        boost::archive::text_iarchive ia(ifs);
        A a;
        ia >> a;
    }

    return 0;
}
question from:https://stackoverflow.com/questions/65876814/input-stream-problem-when-using-stdarray

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I didn't see what could be wrong. Then I looked with asan/ubsan and found domain conversion issues: http://coliru.stacked-crooked.com/a/edee75a22450d9ee

At first I thought maybe there would be a bug in a specific version of Boost[1]. Then it dawned on me.

There are benign warnings:

g++ -std=c++17 -O2 -Wall -pedantic -pthread main.cpp -fsanitize=address,undefined -lboost_serialization && ./a.out
/usr/local/include/boost/serialization/singleton.hpp:181:12: runtime error: reference binding to null pointer of type 'const struct extended_type_info_typeid'
/usr/local/include/boost/serialization/singleton.hpp:181:12: runtime error: reference binding to null pointer of type 'const struct oserializer'
/usr/local/include/boost/serialization/singleton.hpp:181:12: runtime error: reference binding to null pointer of type 'const struct extended_type_info_typeid'
/usr/local/include/boost/serialization/singleton.hpp:181:12: runtime error: reference binding to null pointer of type 'const struct iserializer'
/usr/local/include/boost/serialization/singleton.hpp:181:12: runtime error: reference binding to null pointer of type 'const struct extended_type_info_typeid'
/usr/local/include/boost/serialization/singleton.hpp:181:12: runtime error: reference binding to null pointer of type 'const struct extended_type_info_typeid'
/usr/local/include/boost/serialization/singleton.hpp:181:12: runtime error: reference binding to null pointer of type 'const struct oserializer'
/usr/local/include/boost/serialization/singleton.hpp:181:12: runtime error: reference binding to null pointer of type 'const struct extended_type_info_typeid'
/usr/local/include/boost/serialization/singleton.hpp:181:12: runtime error: reference binding to null pointer of type 'const struct iserializer'
/usr/local/include/boost/serialization/singleton.hpp:181:12: runtime error: reference binding to null pointer of type 'const struct extended_type_info_typeid'

And then we got the domain error:

/usr/local/include/boost/archive/text_oarchive.hpp:65:50: runtime error: load of value 255, which is not a valid value for type 'bool'

Notice how it is the oarchive that runs into them, and confirm:

debug: "22 serialization::archive 17 0 0 0 0 3 -2049146224 32767 -2049145920 1
"

Those are... indeterminate values. Not a big problem for a complete integral domain, but it is for bool. So, fix your initialization:

struct A {
    std::array<int, 3> mat {};
    bool b {};

    template <class Ar> void serialize(Ar& ar, unsigned) {
        ar & mat & b;
    }
};

Of course, you can use other styles:

std::array<int, 3> mat = {0,0,0};
bool b = false;

Or the old-fashioned constructor:

std::array<int, 3> mat;
bool b;

A(std::array<int, 3> mat = {}, bool b = {}) : mat(mat), b(b) {}

Etc. as long as you make sure you initialize your member data.

Fixed On COliru

#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/serialization/array.hpp>
#include <iomanip>
#include <iostream>
#include <sstream>
#include <boost/version.hpp>

struct A {
    std::array<int, 3> mat = {0,0,0};
    bool b = false;

    template <class Ar> void serialize(Ar& ar, unsigned) {
        ar & mat & b;
    }
};

int main() {
    std::stringstream ss;
    {
        boost::archive::text_oarchive oa(ss);
        A a;
        oa << a;
    }

    std::cout << "BOOST_VERSION: " << BOOST_VERSION << "
";
    std::cout << "debug: " << std::quoted(ss.str()) << "
";

    {
        boost::archive::text_iarchive ia(ss);
        A a;
        ia >> a;
    }
}

Prints

BOOST_VERSION: 107500
debug: "22 serialization::archive 18 0 0 0 0 3 0 0 0 0
"

[1] This is what a wild goose chase looks like


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...