使用boost :: serialization,在可变成员中序列化包含缓存的派生值的对象的“最佳”方法是什么?
class Example
{
public:
Example(float n) :
num(n),
sqrt_num(-1.0)
{}
// compute and cache sqrt on first read
float get_sqrt() const
{
if(sqrt_num < 0)
sqrt_num = sqrt(num);
return sqrt_num;
}
template <class Archive>
void serialize(Archive& ar, unsigned int version)
{ ... }
private:
float num;
mutable float sqrt_num;
};
出于维护原因,我想避免将serialize()拆分为单独的save()和load()方法。
序列化的一个次优实现:
template <class Archive>
void serialize(Archive& ar, unsigned int version)
{
ar & num;
sqrt_num = -1.0;
}
它处理反序列化的情况,但在序列化的情况下,缓存的值被终止,必须重新计算。
在这种情况下,最佳做法是什么?
答案 0 :(得分:3)
拆分保存和加载方法并不意味着您必须维护两个序列化代码副本。您可以拆分它们,然后使用通用功能再次将它们连接起来。
private:
friend class boost::serialization::access;
BOOST_SERIALIZATION_SPLIT_MEMBER()
template <class Archive>
void save(Archive& ar, const unsigned int version) const {
const_cast<Example*>(this)->common_serialize(ar, version);
}
template <class Archive>
void load(Archive& ar, const unsigned int version) {
common_serialize(ar, version);
sqrt_num = -1;
}
template <class Archive>
void common_serialize(Archive& ar, const unsigned int version) {
ar & num;
}
你可能已经注意到了const_cast
。对于这个想法,这是一个不幸的警告。虽然serialize
成员函数对于保存操作是非const的,但save
成员函数需要是const。但是,只要你序列化的对象最初没有被声明为const,就可以安全地将其丢弃,如上所示。文件briefly mentions the need to cast for const members;这是类似的。
通过上述更改,您的代码将为ex1
和ex2
正确打印“2”,您只需维护序列化代码的一个副本。 load
代码仅包含特定于重新初始化对象内部缓存的代码; save
函数不会触及缓存。
答案 1 :(得分:2)
您可以检查Archive::is_loading
字段,并加载缓存的值(如果是的话)。
template <class Archive>
void serialize(Archive& ar, unsigned int version)
{
ar & num;
if(Archive::is_loading::value == true)
sqrt_num = -1.0;
}