【问题标题】:How to work Boost serialization with pointers with non-default constructors如何使用具有非默认构造函数的指针进行 Boost 序列化
【发布时间】:2018-01-12 17:46:13
【问题描述】:

我有点吃不消了。我正在使用 boost::serialization 来保存/加载内存中的指针。节省部分,我没有问题。我能够验证序列化类能够毫无问题地保存指针。附带说明一下,指针类是我创建的自定义类。

一些背景。我正在使用 wxwidgets 库来创建 GUI。我正在使用最新版本(v3.1.0)。该对象继承自 wxGLCanvas 类。这需要一个指向父窗口的指针。该类用于在屏幕上绘制网格,用户可以通过放置几何形状(主要是正方形、弧线和线条)与网格进行交互。每个形状都是它自己的类。在我的班级中,我有一些数据类型来指定网格步长、相机的位置、缩放级别和几何形状矢量。所有这些都可以被保存。请注意,我的课程也指定了其他数据类型,但我没有保存这些数据类型,因此它们与讨论无关。附带说明一下,有问题的类称为 modelDefinition

现在,我们来到类的加载部分。我目前的实现是这样的:

void MainFrame::load(string filePath)
{
    std::ifstream loadFile(filePath);

    if(loadFile.is_open())
    {
        modelDefinition temp(this, wxPoint(6, 6), this->GetClientSize(), _problemDefinition, this->GetStatusBar());
        //modelDefinition tempDefintion = (*_model);
        boost::archive::text_iarchive ia(loadFile);

        ia >> _problemDefinition;

        ia >> temp;

        temp.copyModel(*_model);
        //*_model = temp;

        //(*_model) = tempDefintion;
        _model->Refresh();
    }
}

复制功能的实现:

    void copyModel(modelDefinition &target)
    {
        target.setGridPreferences(_preferences);
        target.setEditor(_editor);
        target.setZoomX(_zoomX);
        target.setZoomY(_zoomY);
        target.setCameraX(_cameraX);
        target.setCameraY(_cameraY);
    }

我的想法是,我创建一个临时变量并将其初始化为我需要的值。目前,它是空的。然后,我将数据加载到临时变量中,然后将所需的数据结构复制到我的主变量中。但是,程序在ia >> temp 处崩溃。我现在不知道为什么。我进入调试器,崩溃后无法访问调用堆栈。我有一种感觉,它在 boost 库中崩溃了。我确实在 modelDefinition 的 serialize 函数中放置了一个断点,但程序从未成功。

我确实遇到过这个论坛帖子: Boost serialization with pointers and non-default constructor

说实话,我不太确定它是否适用于我。我正在尝试一种方法,但到目前为止我找不到任何适用于我的理由。

这里是modelDefinition构造函数的声明:

modelDefinition::modelDefinition(wxWindow *par, const wxPoint &point, const wxSize &size, problemDefinition &definition, wxStatusBarBase *statusBar) : wxGLCanvas(par, wxID_ANY, NULL, point, size, wxBORDER_DOUBLE | wxBORDER_RAISED)

par 必须有一个值。不接受空值。我确实看到论坛帖子确实覆盖了加载函数并获取了值并将它们传递给类的构造函数。然而,在我的例子中,par 是一个this 指针,我无法序列化函数并将this 加载回程序中(此外,this 将在每个函数调用时更改)。 this 指回父窗口。并且在不同的命名空间中覆盖加载函数会阻止我将 this 传递给函数。因此,基本上,该选项不可行(除非我遗漏了什么)。

再次,由于我无法将 NULL 传递给 wxGLCanvas 构造函数,因此该选项不可用:

modelDefinition _model = new modelDefinition();
modelDefinition::modelDefinition() : wxGLCanvas(NULL, 0)

而且我相信这个选项也不在讨论范围内,因为与画布关联的父窗口位于不同的命名空间中:

template<class Archive>
inline void load_construct_data(
    Archive & ar, modelDefintion * foo, const unsigned int file_version
){
    double test;// There would be more after this but to simplify the posting, I am just throwing this in here.

    ar >> test;

    ::new(modelDefintion)_model(this, test); // Yeah, I don't think that this is going to work here.
}

同样,this 需要指向父窗口,我认为我无法访问。

所以现在,我对自己的选择有点迷茫。到目前为止,我认为我将继续研究第一个案例,看看程序在哪里崩溃。

虽然,我真的可以借助某人的帮助来解决这个问题。在无法保存继承对象的数据(因为 modelDefinition 继承自 wxGLCanvas 数据类型并且我无法保存此数据类型)的情况下,如何加载非默认构造函数指针的数据结构?

是的,我知道最小的例子。我需要一些时间来创建一个最小的例子。如果论坛人们需要它来有效地提出解决方案,那么我会这样做并在这里发布。但同样,这需要时间,而且可能会相当长。

【问题讨论】:

  • I go into the debugger and I do not get access to the call stack after the crash. 这太奇怪了。您运行的是调试版还是优化版?
  • @SergeyA 是的,没错。有趣的是,我正在优化它以进行调试。我仍在检查设置以确保我没有错过任何东西。当我在终端中运行程序时,它崩溃并产生了这个错误输出:*** Caught unhandled std::exception of type "N5boost7archive17archive_exceptionE", what() = "input stream error"; terminating

标签: c++ pointers serialization boost


【解决方案1】:

是的,加载/保存构造数据是处理非默认构造的工具。

您的问题不同:您需要来自外部的状态,因为您试图在构造期间加载需要状态的对象,但它从未被保存在首位。如果是这样,您可以重新创建父窗口,就像它在序列化期间存在一样。

我在这里看到的唯一“解决方法”是使用全局状态(即通过(线程)全局变量访问它)。

我不推荐,但你处于困境中,所以考虑解决方法是件好事,即使是糟糕的解决方法

一旦您从旧式档案中抢救出您的数据,我建议您将其序列化为一种格式

  • 保存所有必需的构造数据
  • 序列化不绑定到 GUI 元素的数据结构

当然我不知道这里的总体目标,所以我不能说哪种方法更合适,但是如果没有上下文,我总是会努力分离关注点,即将序列化与任何 UI 元素。

【讨论】:

  • 您好,谢谢您的回复。我考虑了您关于关注点分离和从 UI 元素中解耦序列化的答案,我想出了一个解决方案。我需要保存大约 6 件东西,其中 4 件是双打的。对于其他 2 个,它们具有默认构造函数并且不是指针。我现在只从 modeDefinition 类中提取所需的数据结构并保存它们而不是整个类。该解决方案完美运行。谢谢。
猜你喜欢
  • 1970-01-01
  • 2022-09-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-11-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多