促进不透明类型的序列化

Posted

技术标签:

【中文标题】促进不透明类型的序列化【英文标题】:boost serialization of opaque types 【发布时间】:2012-09-09 21:02:25 【问题描述】:

我希望能够序列化一个 Windows HANDLE:

typedef void *HANDLE

如果我尝试使用以下代码进行编译:

struct Foo

    HANDLE file;

protected:
    friend class boost::serialization::access;

    template<class Archive>
    void serialize(Archive & ar, const unsigned int /*version*/)
    
        ar & file;
    
;

我得到编译错误:

c:\projects\3rdparty\src\boost\include\boost/mpl/print.hpp(51) : warning C4308: negative integral constant converted to unsigned type
        c:\projects\3rdparty\src\boost\include\boost/serialization/static_warning.hpp(92) : see reference to class template instantiation 'boost::mpl::print<T>' being compiled
        with
        [
            T=boost::serialization::BOOST_SERIALIZATION_STATIC_WARNING_LINE<98>
        ]
        c:\projects\3rdparty\src\boost\include\boost/archive/detail/check.hpp(98) : see reference to class template instantiation 'boost::serialization::static_warning_test<B,L>' being compiled
        with
        [
            B=false,
            L=98
        ]
        c:\projects\3rdparty\src\boost\include\boost/archive/detail/oserializer.hpp(313) : see reference to
function template instantiation 'void boost::archive::detail::check_object_tracking<T>(void)' being compiled
        with
        [
            T=Foo
        ]
        c:\projects\3rdparty\src\boost\include\boost/archive/detail/oserializer.hpp(525) : see reference to
function template instantiation 'void boost::archive::detail::save_non_pointer_type<Archive>::invoke<T>(Archive &,T &)' being compiled
        with
        [
            Archive=boost::archive::text_oarchive,
            T=Foo
        ]

但如果我将file 更改为int,一切都很好。 如何告诉 boost 将 HANDLE 序列化为整数?

谢谢

【问题讨论】:

【参考方案1】:

HANDLE 是在winnt.h 中定义的特定于 Windows API 的数据类型。根据MSDN,

对象的句柄。 该类型在WinNT.h 中声明如下:

typedef PVOID HANDLE;

所以,现在我们看到HANDLE 实际上只是void *——代表一个对象的句柄。想想你想要做什么;将 指针 序列化到 Windows API 中的某个对象是否有意义?

相反,尝试序列化检索等效HANDLE 所需的内容;从成员的名字来看,我猜你用的是CreateFile——所以,你需要知道......

文件名 所需的访问权限(例如GENERIC_READ | GENERIC_WRITE) 分享模式(如FILE_SHARE_DELETE) 可选的安全属性 创作倾向(即CREATE_NEWTRUNCATE_EXISTING等) 文件或设备标志和属性 (可选)模板文件 -- 用于在创建文件时复制其属性

现在,如果你真的不想这样做——你肯定你想要指针值——也许在通过转换后尝试序列化它reinterpret_caststd::intptr_tstd::uintptr_t可能在 C++11 的 cstdint 中定义)。

ar & reinterpret_cast<std::intptr_t>(file);

...那么您应该将其与以下内容结合起来(反序列化时):

std::intptr_t _file;
ar & _file;
HANDLE file = std::reinterpret_cast<HANDLE>(_file);

【讨论】:

是的,这是有道理的。我正在做 IPC,我要发送的结构字段之一是重复的 HANDLE。谢谢 @BevanCollins 确保file 是目标进程的有效重复句柄(即来自DuplicateHandle)...然后我想只需使用intptr_t 我会在序列化时将reinterpret_cast 更改为static_cast。 See here 了解更多详情。 @BevanCollins 对,这就是为什么我建议转换为 std::intptr_t 的原因——这有望解决问题。如果您知道环境中指针的大小(Windows 与此非常一致),您可以执行技术上未定义的行为(并依赖您的环境提供一致性)并尝试转换为整数类型,如 INT32 或 @ 987654352@,而不是。 @JesseGood 请参阅this reference on reinterpret_cast...“任何指针都可以转换为任何大到足以容纳指针值的整数类型(例如std::uintptr_t)”。 C++11 允许这样做。【参考方案2】:

最终通过拆分序列化来解决问题。虽然看起来像一个黑客:

struct Foo

    HANDLE file;

protected:
    friend class boost::serialization::access;

    template<class Archive>
    void save(Archive & ar, const unsigned int /*version*/) const
    
        unsigned int _file = reinterpret_cast<unsigned int>(file);
        ar & _file;
    

    template<class Archive>
    void load(Archive & ar, const unsigned int /*version*/)
    
        unsigned int _file;
        ar & _file;
        file = reinterpret_cast<HANDLE>(_file);
    
    BOOST_SERIALIZATION_SPLIT_MEMBER()
;

【讨论】:

LOL - 好吧,HANDLE 是个黑客。猜猜它需要一个人知道一个!

以上是关于促进不透明类型的序列化的主要内容,如果未能解决你的问题,请参考以下文章

使用共享指针和模板促进序列化

SpringBoot+MyBatis Plus对Map中Date格式转换的处理

python--使用pickle序列化对象

csharp オバケはDOTween.Sequenceで不透明度変更を缲り返す。倒されたら序列を止める

20161115笔记(IO流等)

为啥 ktor 序列化不支持序列化不同元素类型的集合?