【问题标题】:Can't get C++ Boost Pointer Serialization to work无法使 C++ Boost 指针序列化工作
【发布时间】:2015-03-06 15:05:37
【问题描述】:

此问题与列为重复的问题不同: Boost c++ serializing a char * 我没有使用 shared_ptr,并且我可以完全访问我的课程的内部。

我能找到的最接近的响应是在Store a vector of pointers to custom objects to file 中,我通过搜索编译器错误找到了它。

但是,那里给出的答案并不清楚,至少对我来说不是。它指向 boost 文档,这表明我在这里列出的简单代码应该可以工作。在对通过指针序列化对象的所有内务进行分类之后,boost 文档这样说。

此序列化库解决了上述所有注意事项。

如果我必须一次写入一个 char[] 一个字符,或者如果我必须取消引用容器中的所有指针对象并将它们分解为它们的组成 POD 部分,首先将它们的大小以字节为单位写入流,以便用boost序列化,那么使用boost似乎没有多大意义。这是工作的最大份额。创建一个文本输出流并将字节注入其中是微不足道的。

我并不是说我可能对文档有阅读理解问题,但根据我对所读内容的理解,下面的代码 sn-p 应该可以工作。但是,此代码会发出以下编译器错误。所以,我一定是遗漏了一些东西,但我就是看不到它,所以这就是我寻求帮助的原因。

在下面的代码sn-p中简单指出故障点怎么样?或者,更好的是,提供一个有效的 sn-p?

/usr/include/boost/serialization/access.hpp:118:9: error: ‘class boost::ptr_vector<std::basic_string<char> >’ has no member named ‘serialize’
         t.serialize(ar, file_version);
         ^
#include <fstream>
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>

class A {
public:
        A(){}

        char c;
        char *name;

        friend boost::serialization::access;
        template<class Archive>

        void serialize(Archive& ar, unsigned version) 
        {
                ar &  name;
        }
};

main()
{
        A a;
        a.name = (char *)"this is a test";

        std::ofstream ofs("table.txt");
        boost::archive::text_oarchive os(ofs);
        os << a;
}

我可以序列化 int、char 甚至 STL 类型,但我不能用指针序列化任何东西。比如我可以序列化std::vector&lt;std::string&gt;,但是如果我尝试序列化std::vector&lt;std::string *&gt;,就会得到编译错误。

【问题讨论】:

  • @Mr.Kbok 我也在做同样的事情。 \@OP 这对你来说看起来像 HTML 吗?你能“运行 sn-p”吗?
  • 您能提供原始答案的链接吗?我找不到它。
  • 它打印在顶部:i.imgur.com/b7hVWxj.png 如果之前显示页面时出现某种错误,您可能需要刷新浏览器。
  • 哦,好吧。答案就在链接的副本中 - 如果您正在寻找它。我在这里写了一个答案。我同意“替代案例”在该答案中并不是特别出色,但话又说回来,无论如何,由于我的回答中证明的原因,没有人应该推荐。
  • 回复。 “简单地指出下面代码 sn-p 中的故障点怎么样?或者,更好的是,提供一个可以工作的 sn-p?” - 你如何意识到人们可能没有时间?我向您指出了现有的答案,假设您阅读了它的含义,并希望您能在 4 小时前得到答案。你没有有权得到答案。我试图提供帮助。

标签: c++ serialization boost


【解决方案1】:

如果我必须一次写入一个 char[] 一个字符,或者如果我必须取消引用容器中的所有指针对象并将它们分解为它们的组成 POD 部分,首先将它们的大小以字节为单位写入流,以便用boost序列化,那么使用boost似乎没有多大意义。

是的。但是您正在尝试序列化指针。指向char 的指针应该被序列化为什么?当然T* 应该序列化一个动态分配的T,不是吗?所以你会期望序列化单个char,除非namenullptr

或者您是否希望对每个序列化的字符进行完整的对象跟踪?

这里的重点是您选择了指向原始类型的原始指针。指针缺少必要的信息。因此,您有责任添加信息。如果您觉得这乏味,您可以随意使用 C++ 类型。

顺便说一句,这在 C++03 及更高版本中是不合法的:

a.name = (char *)"this is a test";

char const(&amp;)[15]char * 的静态转换将放弃 const 限定条件。无论如何,您的编译器都应该拒绝此代码。

这是我的看法(使用std::string):

#include <boost/serialization/string.hpp>
#include <boost/archive/text_oarchive.hpp>

class A {
  public:
    std::string name;
    template <class Archive> void serialize(Archive &ar, unsigned) {
        ar & name;
    }
};

int main() {
    A a { "this is a test" };
    boost::archive::text_oarchive os(std::cout);
    os << a;
}

顺便说一句,链接的重复问题的标题与您在此处尝试执行的操作完全匹配:Boost c++ serializing a char *,并且接受的答案显示完全相同的解决方案。

如果你真的坚持,你当然可以毫无荣耀地去拼一些 C 风格的代码:

#include <boost/serialization/serialization.hpp>
#include <boost/serialization/binary_object.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <cstring>
#include <cstdlib>

class A {
  public:
    A(char const* sz = nullptr) : name(sz? strdup(sz) : nullptr) {}
    A(A const&) = delete;
    A& operator=(A const&) = delete;

    ~A() { free(name); }

  private:
    char* name;

    template <class Archive> void save(Archive &ar, unsigned) const {
        bool have_name = name;
        ar & have_name;

        if (have_name)
        {
            size_t len = strlen(name);
            ar & len;
            ar & boost::serialization::make_binary_object(name, len);
        }
    }

    template <class Archive> void load(Archive &ar, unsigned) {
        bool have_name = name;
        ar & have_name;

        if (!have_name)
        {
            free(name);
            name = nullptr;
        } else
        {
            size_t len = 0;
            ar & len;

            name = static_cast<char*>(realloc(name, len));
            ar & boost::serialization::make_binary_object(name, len);
        }
    }

    friend class boost::serialization::access;
    BOOST_SERIALIZATION_SPLIT_MEMBER()
};


int main() {
    A a { "this is a test" };
    boost::archive::text_oarchive os(std::cout);
    os << a;
}

但是所有这些让你获得的好处是代码量增加了 6 倍,价值语义受损,完全放弃了关注点分离,还有很多潜在的错误(你有没有想到 name==nullstrlen(name)==0 之间的区别?目前我的实现 @ 987654322@。我将把它作为练习留给你,读者,在这里提出密封处理)和......甚至不可读的字符串输出。

是的,当然make_array 会给你14 116 104 105 115 32 105 115 32 97 32 116 101 115 116 而不是dGhpcyBpcyBhIHRlc3Q=,但这样的存储效率非常低,而且仍然不适合人类阅读。

【讨论】:

  • 感谢您考虑周全的回复。所以,我想简短的回答是避免使用指向对象的指针进行序列化。序列化指向类的指针向量,例如'vector' 会引起同样的复杂情况,而 'vector' 开箱即用。
  • 我要解决的问题是与 C 代码交互,该代码收集大量信息以供以后分析。我必须使用 C 来收集数据,因为它使用的头文件无法在 c++ 中编译。
  • extern "C" 应该会有所帮助。而且无论如何您都不能在 C 模式下使用 Boost Serialization。如果你还想反序列化,你仍然需要考虑分配内存。
  • 我认为 boost 序列化将是存储数据的好方法,这非常复杂,具有嵌套层次结构和图形的属性。如果不是因为数据的性质,我会简单地使用 fprintf() 并完成它。 :)
  • 了解一下。我在 C 和 C++ 源共享的标头中有 #ifdef __cplusplus extern C。那部分工作得很好。只是 C 用指针提供了所有信息。
猜你喜欢
  • 1970-01-01
  • 2016-04-21
  • 1970-01-01
  • 1970-01-01
  • 2018-11-02
  • 2015-02-13
  • 2014-07-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多