促进不透明类型的序列化
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_NEW
、TRUNCATE_EXISTING
等)
文件或设备标志和属性
(可选)模板文件 -- 用于在创建文件时复制其属性
现在,如果你真的不想这样做——你肯定你想要指针值——也许在通过转换后尝试序列化它reinterpret_cast
到 std::intptr_t
或 std::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格式转换的处理