`
febird
  • 浏览: 256403 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

检查序列化声明的顺序和成员定义的顺序

阅读更多

项目地址:http://code.google.com/p/febird

 

DataIO_is_realdump用来推断一个对象是否可以直接通过dump内存来完成序列化,如果可以,在load/save时会有极大的性能提高。如果dump后,一些成员除了需要byte_swap,而不需要其它任何转化,也可以安全地先dump然后再byte_swap,这样比一个成员一个成员地load/save并且byte_swap要快得多。

但是可以引发一个问题,就是如果序列化声明的顺序和成员定义的顺序不同,并且推断结果表明DataIO_is_realdump为真,真正序列化的顺序就就是成员定义的顺序,和序列化声明的顺序不同,而序列化声明的顺序才是调用者真正的意图。

一开始没有仔细考虑这个问题,只是把它丢给使用者,但是这样的错误实在太微妙了,很多时候都不会出错(因为load和save一样),除非load/save一个优化一个没优化,问题才会暴露出来。

认真考虑一下,这个问题其实可以检测出来,但不是在编译时,只能在运行时。只要每次调用 operator& 的时候记录参数(某个成员)的地址,下个成员的地址如果小于等于这个地址,就表明出了错。再进一步,如果某个“成员”的地址出了那个对象的地址范围,更是一个错误,如果这个成员是个指向其他对象的引用,则有可能不是一个错误,这也是可以推断出来的,引用类型本来就不是dumpable的,可以用trait去除。以下是实现代码:

template<class DataIO, class Outer, int Size, bool Dumpable>
struct DataIO_is_realdump
{
	BOOST_STATIC_CONSTANT(int, size = Size);
	typedef boost::mpl::bool_<Dumpable> is_dump;

#if (defined(_DEBUG) || !defined(NDEBUG)) && !defined(DATA_IO_DONT_CHECK_REAL_DUMP)
	const Outer* address;
	const char*  prev_member;
	DataIO_is_realdump(const Outer* p, const void* prev_member)
		: address(p), prev_member((const char*)prev_member) {}
	DataIO_is_realdump(const Outer* p)
		: address(p), prev_member((const char*)p) {}
#else
	DataIO_is_realdump(const Outer*, const void* = 0) {}
#endif

	template<class T>
	void check_member_order(const T& x, ::boost::mpl::true_)
	{
#if (defined(_DEBUG) || !defined(NDEBUG)) && !defined(DATA_IO_DONT_CHECK_REAL_DUMP)
	// if member declaration order of &a&b&c&d is different with where they defined in class
	// here will raise an assertion fail
	//
	// 如果成员序列化声明的顺序 &a&b&c&d 和它们在类中定义的顺序不同
	// 这里会引发一个断言
	// 如果序列化了一个非类的成员(比如 &a&b&c&d 中可能一个标识符引用了不是雷成员的某个变量),也会引发断言
		assert((const char*)&x >= (const char*)address);
		assert((const char*)&x <= (const char*)address + sizeof(Outer) - sizeof(T));
		if (prev_member != (const char*)address)
			assert(prev_member < (const char*)&x);
#endif
	}
	template<class T>
	void check_member_order(const T&, ::boost::mpl::false_)
	{
	}

	template<class T>
	DataIO_is_realdump<DataIO, Outer, Size+sizeof(T), boost::mpl::bool_<Dumpable && DataIO_is_dump<DataIO, T>::value>::value>
	operator&(const T& x)
	{
		check_member_order(x, ::boost::mpl::bool_<Dumpable && DataIO_is_dump<DataIO, T>::value>());
		return DataIO_is_realdump<DataIO, Outer, Size+sizeof(T), boost::mpl::bool_<Dumpable && DataIO_is_dump<DataIO, T>::value>::value>(address, &x);
	}
};

 

其中,check_member_order只对“根据目前的推断,Outer对象如果是dumpable,就执行检查,反之则啥都不做。

当然,需要注意的就是,在外部初始化时,调用DataIO_is_realdump(const Outer* p),而 DataIO_is_realdump(const Outer* p, const void* prev_member)仅在递归(严格讲并非递归)推断时,才使用。因此初始化传入的那个p,必须就是operator&中的对象属主,这只能由调用者保证,幸好,这个调用者只是DataIO库。

 

项目地址:http://code.google.com/p/febird

1
0
分享到:
评论

相关推荐

    C#对象序列化与反序列化

    - **强制指定成员的序列化顺序**:使用`[XmlElement(Order = n)]`特性来控制成员的序列化顺序。 - **自定义序列化行为**:通过实现`IXmlSerializable`接口来自定义序列化逻辑。 - **序列化设置XML命名空间**:使用`...

    Qt自定义结构序列化

    - 为保证序列化的稳定性,应保持序列化顺序与成员变量声明顺序一致。 - 自定义类型的成员变量应尽可能使用Qt支持的基本类型,否则可能需要为嵌套类型实现额外的序列化逻辑。 5. **QtSerializeDemo示例** - `...

    序列化、反序列化源码

    为了正确地反序列化,需要确保数据的结构与序列化时一致,包括类型、顺序和数量。 在C++中实现序列化和反序列化,开发者通常需要考虑以下几点: 1. **类型安全**:确保在反序列化过程中,数据类型与原始对象的成员...

    asp.net序列化cookie-vs2010版本

    1. 定义要序列化的类: ```csharp public class MyData { public string Name { get; set; } public int Age { get; set; } } ``` 2. 创建对象实例,并填充数据: ```csharp MyData data = new MyData() {...

    序列化和反序列化

    这可以用来排除某些字段、指定序列化顺序或提供特殊的序列化逻辑。 总之,序列化和反序列化是软件开发中不可或缺的技术,它们使得对象的状态可以被持久化、在网络中传递或在不同上下文中复用。理解和熟练掌握各种...

    Protocol buffers 反序列化 一键protoc反序列化

    Protocol Buffers,通常简称为protobuf,是Google开发的一种数据序列化协议,用于高效地编码和解码结构化数据。它提供了语言无关、平台无关的接口,使得数据可以在各种不同的应用程序之间进行交换。在本主题中,我们...

    C#自定义序列化ISerializable的实现方法

    在`GetObjectData`方法中,我们通常会按照字段的声明顺序添加值,确保在反序列化时能够正确恢复。对于继承的类,如果基类也实现了ISerializable接口,我们需要特别处理基类的字段,避免重名导致的问题。 总的来说,...

    基于C#+XML实现的对象序列化与反序列化的程序例子代码

    这里需要注意的是,序列化和反序列化要求类的结构保持一致,包括属性的类型和顺序。如果XML中的元素与类的属性不匹配,反序列化会失败。 此外,C#还提供了BinaryFormatter类用于二进制序列化,但相比XML,二进制...

    vc++学生信息和课程信息序列化

    为了实现序列化,我们需要在这些类中添加相应的成员函数,如`serialize()`和`deserialize()`。 `serialize()`函数用于将对象转换为字节流,可以使用文件流或者内存流进行操作。例如,可以将每个成员变量通过`...

    hessian序列化规范

    3. 自定义Hessian序列化器以支持自定义类型的序列化和反序列化。 总结,Hessian序列化规范是分布式系统中的重要工具,理解其原理和使用方法,能够帮助我们构建高效、可靠的跨网络通信方案。然而,任何工具都有其...

    Avro 1.8.2 序列化规范

    Avro 1.8.2版本为Hadoop新型序列化框架规范定义了相关细节,提供了标准化的序列化和反序列化机制,可以用于远程过程调用(RPC)和持久化数据的存储。 ### 标题和描述知识点 标题“Avro 1.8.2 序列化规范”直接指出了...

    数据契约之WCF与序列化

    - **Order**: 如果设置,序列化和反序列化会按照成员的定义顺序进行,这对于依赖成员顺序的场景很重要。 - ** EmitDefaultValue**: 如果设置为`true`,即使属性值为默认值,也会在序列化时包含。默认情况下,如果...

    ProtoBuf的介绍以及在Java中使用protobuf将对象进行序列化与反序列化示例代码.rar

    在Java中,这些接口通常是一些静态方法,用于将对象转换为字节流(序列化)和从字节流恢复对象(反序列化)。 **Java中的ProtoBuf使用** 1. **定义.proto文件** 首先,我们需要创建一个.proto文件,例如`Person....

    【数据结构】线性表顺序表(全)测试代码用C语言C++实现动态及静态顺序表的定义、插入、删除 定义线性表节点的结构.pdf

    在上面的代码中,InitList函数用于初始化顺序表,将所有数据元素设置为默认初始值0,并将当前长度设置为0。PrintList函数用于打印顺序表中的所有数据元素。SetList函数用于设置顺序表中的一个数据元素。ListInsert...

    翻译_Java对象的序列化

    JavaBeans的属性、事件和方法可以通过序列化来保存和恢复状态,使得组件的配置和状态能够在不同的使用场景间保持一致。 为了实现对象的序列化,你需要让类实现Serializable接口,这个接口没有定义任何方法,只是...

    dubbo注意的问题,注入问题,接口中的bo应该实现序列化,否则服务注册失败

    2. `ChainDefinitionSectionMetaSource.java`: 这个文件可能与配置或者元数据定义有关,可能用于构建服务的消费或提供者链路,确保服务的完整性和顺序。 3. `FinancialInterfaceAssignInfoController.java`: 这可能...

    DotNetty系列四:自定义协议,序列化类库MessagePack,项目代码

    在自定义协议中引入MessagePack,我们需要先为我们的数据对象定义MessagePack兼容的序列化和反序列化方法。MessagePack提供了一套API,允许我们注册类型并生成对应的序列化和反序列化函数。这样,我们可以在服务器端...

    数据结构之线性表的顺序表示和实现

    SqList.h 文件很可能定义了顺序表的类,包括类的声明和成员函数的原型。可能包含以下内容: 1. 类的声明:`class SeqList`,表示顺序表的数据结构。 2. 成员变量:如一个动态分配的数组,用于存储元素,以及数组的...

    顺序栈验证试验

    顺序栈是一种常见的数据结构,它在计算机科学和编程中扮演着重要的角色。顺序栈是基于数组实现的,其特点是元素的插入(压栈)和删除(弹栈)操作都发生在栈顶,遵循“后进先出”(LIFO,Last In First Out)的原则...

    《数据结构C++版》实验一:线性表的顺序存储结构实验报告

    - 这部分要求实现序列化和反序列化,将顺序表的数据存入和读出文件。这通常涉及到文件流(fstream)的使用,以及序列化数据结构到文件的逻辑。 6. **逻辑删除**: - 逻辑删除并不实际移除元素,而是标记其为已...

Global site tag (gtag.js) - Google Analytics