实现对象跟踪,就像在Boost :: Serialization中一样。

4
我正在为C++对象图实现一个“克隆”函数,其中一部分问题是确保如果有两个指针指向同一对象,则不会对其进行两次克隆。我通过保留map<void*, void*>来实现这一点,将原始对象作为键,克隆版本作为值。在克隆对象时,我使用模板函数检查对象是否在映射中 - 如果是,则返回它以static_cast<T*>的形式,否则,我会克隆它并将原始和克隆保存在映射中,并进行隐式转换为void*
这种方案的问题在于,如果一个对象以不同的类型(例如接口与具体类型)在两个位置引用,那么对void*的转换可能不会产生相同的值。这意味着该对象将被克隆两次。
我在网上寻找现有的解决方案,并意识到Boost.Serialization也必须处理相同的问题。但是在浏览了它的源代码后,我无法找到实际跟踪对象指针的部分。
有人能够提出一个有效的设计建议吗?或者指出Boost代码中执行此操作的部分吗?
2个回答

4
在存储指针之前,使用dynamic_cast<void*>进行转换 - 这将为您提供一个指向最终派生对象的void指针;对于同一对象,这个void指针将具有相同的存储地址。
另请参见此问题

1
那不应该是 dynamic_cast<void*> 吗? - Björn Pollex
这仅适用于多态类型。 - edA-qa mort-ora-y
@edA-qamort-ora-y:“这个方案的问题在于,如果一个对象被不同类型的两个地方引用(例如通过接口与具体类型)”。 - Xeo
@Xeo,他仅举了一个例子,并不像只有这种情况一样,因为序列化通常还必须处理非多态类型 - 这是boost序列化同样处理的。 - edA-qa mort-ora-y
是的,它需要同时适用于多态和非多态类型,因为它是一个模板函数,用户可以(并且确实)使用两者进行实例化。您能详细说明一下对于非多态类型使用dynamic_cast<void*>存在的问题吗? - exclipy
@exclipy:嗯,问题不在于void*,而在于dynamic_cast只能用于多态类型。 :/ - Xeo

1

我不相信boost序列化会以某种超级聪明的方式处理这个问题。看看base_object函数--你似乎必须手动指定基类是什么。从这里很明显可以知道如何获得相同的指针。还要注意,对于序列化派生类,只有虚拟类才能以正确的方式保存,非虚拟类(例如标准布局类型)必须序列化派生类。我不知道他们在这种情况下是否处理共享指针。

因此,基本思想是,如果您有一个虚拟类,则基类必须具有某种“串行”函数。如果您将其转换为此基类,则具有公共指针,仍然可以调用虚拟串行函数。

您最好只需创建一个全局的identify<T>模板,并为所有需要它的类型进行专门化。可能会出现错误,但绝不意味着boost方法可以避免错误。

我已经做了很多与boost序列化相关的工作,但避免了指针逻辑--它变得非常混乱,所以我基本上不进行那个级别的序列化(我的序列化数据中没有指针)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接