使用std::memcpy拷贝包含boost::any成员的对象是否会引发未定义行为?
问题解答
为什么Data对象大小固定为8?
boost::any的核心实现逻辑是把实际存储的数据放在堆内存中,类本身只保存一个指向堆内存的指针。64位系统下指针的固定大小为8字节,因此不管你存储的内容多大、是什么类型,Data类本身的内存大小永远等于指针大小,也就是你看到的8字节,实际数据并不存在于类对象的内存区间里。
这段代码是否存在未定义行为?
是,这是典型的未定义行为。
memcpy仅适用于**平凡可复制(TriviallyCopyable)**类型,boost::any有自定义的拷贝构造、析构函数,不属于平凡可复制类型,直接用memcpy拷贝会跳过类本身定义的复制逻辑,完全不符合C++标准要求。- 当前示例能正常运行只是巧合:示例中
src是栈变量,生命周期覆盖了dst的使用周期,memcpy只是浅拷贝了boost::any内部的堆指针,此时指针指向的内存还未被释放,所以看起来正常。只要场景稍有变化,比如src先被析构释放了内部内存,dst的指针就会变成野指针,访问会直接崩溃;另外你调用free释放dst内存时,没有调用Data的析构函数,boost::any内部的堆内存会直接泄漏。 - 你原本的跨应用传输场景更是完全不可行:不同应用的地址空间完全独立,你传过去的指针在对端进程中是无效地址,根本无法访问对应的数据,一定会崩溃。
如何正确实现需求?
你需要的是序列化机制:把boost::any存储的实际数据和类型信息一起转换成连续的无歧义字节流,传输到对端后再反序列化为对应类型的对象,不能直接拷贝对象的内存布局。
具体可参考两种实现思路:
- 如果可以枚举所有可能存储在
boost::any中的类型:自定义序列化逻辑,为每种类型分配唯一的类型标识,序列化时先写入类型标识,再写入该类型对应的数据字节;反序列化时先读取类型标识,再按照对应类型的规则解析数据,最后存入boost::any即可。 - 如果类型不可枚举,可以使用成熟的序列化库:比如Boost.Serialization,它原生支持
boost::any的序列化(只需提前注册所有用到的类型),序列化得到的字节流可以随意拷贝、网络传输,到对端反序列化即可得到可用的Data对象。
内容的提问来源于stack exchange,提问作者tjwrona
相关产品推荐
相关产品推荐

