您好,欢迎访问三七文档
当前位置:首页 > 行业资料 > 纺织服装 > c 开发指导之使用编译期的契约:约束在编译期发现程序的错误
C++开发指导之使用编译期的契约:约束,在编译期发现程序的错误利用C/C++编译器对源程序进行编译的时候会检查语法错误和计算常量等特性,可以给我们的C/C++源代码添加一些编译期的契约,要求源代码按一定的规则使用,这样的好处是可以减少很多使用错误,减少软件的bug,因为这些bug在代码编译的时候就发现了,不用等测试或现场使用时才发现。下面举一些编译期的契约,约束例子。1.must_have_base()必须继承自template<typenameD,typenameB>structmust_have_base{~must_have_base(){void(*p)(D*,B*)=constraints;}private:staticvoidconstraints(D*pd,B*pb){pb=pd;}};模板原理:子类指针可以直接赋值给基类指针。使用场景举例:classBase{public:Base();};template<classT>classC:must_have_base<T,Base>{/*...*/};这个例子要求你使用模板类C时,模板参数必须继承自类Base。2.must_be_subscriptable()必须可以按下标方式访问template<typenameT>structmust_be_subscriptable{staticvoidconstraints(Tconst&T_is_not_subscriptable){sizeof(T_is_not_subscriptable[0]);}};模板原理:就是按下标方式来访问进行检验。使用场景举例:template<classT>voidfun(T&t){must_be_subscriptable<T>constraint;//t[0]?//...}要求输入参数要求可以用下标来访问3.must_be_subscriptable_as_decayable_pointer()必须可以按下标方式访问,并且可以退化为原生指针template<typenameT>structmust_be_subscriptable_as_decayable_pointer{staticvoidconstraints(Tconst&T_is_not_decay_subscriptable){sizeof(0[T_is_not_decay_subscriptable]);}};模板原理:原生指针的特性,通过下标访问可以反过来,就是即可以这样pointer[offset]使用指针,也可以这样offset[pointer]使用指针。4.must_be_pod()必须为POD类型POD类型:POD意思是“plain-old-data”(C++-98:1.8;5),它是C++中的一个重要概念。POD类型必修满足以下条件:将组成它的一个对象的各字节拷贝到一个字节数组中,然后再将它们重新拷贝回原先的对象所占的存储区中;此时对象应该仍具有它原来的值。POD类型定义:标量类型、POD结构类型、POD联合类型,这些类型的数组,以及这些类型以const/volatile修饰的版本。POD结构:一个聚合体类,其任何非静态成员的类型都不能是如下任意一种:指向成员的指针、非POD联合,以及以上这些类型的数组或引用,同时该聚合体类不允许包含用户自定义的拷贝赋值操作符和用户自定义的析够函数。POD类型的重要作用:POD类型允许C++与C交互!template<typenameT>structmust_be_pod{staticvoidconstraints(){union{TT_is_not_POD_type;};}};模板原理:利用POD类型可以放在union中实现这个约束。使用场景举例:template<typenameT>unionmust_be_pod{Tt;};template<typenameT>voidSafeZeroMemory(T*p,size_tsize){must_be_pod<T>();memset(p,0,size);}classA{public:~A(){}voidReset(){_value=0;}private:int_value;};classB{public:voidReset(){_value=0;}private:int_value;};classC{private:int_value;};voidTestImpl(){Aa;Bb;Cc;inti=0;int*p=0;SafeZeroMemory(&a,sizeof(a));//编译失败SafeZeroMemory(&b,sizeof(b));//编译通过SafeZeroMemory(&c,sizeof(c));//编译通过SafeZeroMemory(&i,sizeof(i));//编译通过SafeZeroMemory(&p,sizeof(p));//编译通过};上面例子中,类A有析构函数,因此它不是POD结构。一个类或结构如果有构造函数、析构函数、复制构造函数、赋值函数、或虚函数、它从非POD的类或结构继承或者从多个类继承,都不是POD结构。5.must_be_same_size()大小必须相同template<typenameT>structsize_of{enum{value=sizeof(T)};};template<>structsize_of<void>{enum{value=0};};template<typenameT1,typenameT2>structmust_be_same_size{public:~must_be_same_size(){void(*pfn)(void)=constraints;(void)(pfn);}private:staticvoidconstraints(){structmust_be_same_size_{intT1_must_be_same_size_as_T2:size_of<T1>::value==size_of<T2>::value;};}};模板原理:已命名位域不能有零宽度。使用场景举例:template<typenameT1,typenameT2>voidObjCopy(T1&l,constT2&r){must_be_same_size<T1,T2>();must_be_pod<T1>();must_be_pod<T2>();memcpy(&l,&r,sizeof(l));}{intfoo;};structB{intfoo;};structC{charfoo;};voidTestImpl(){Aa;Bb;Cc;ObjCopy(a,b);//编译通过ObjCopy(a,c);//编译失败}上述例子中,结构C的大小和结构A的不同,因此编译失败。作者:lzy0168
本文标题:c 开发指导之使用编译期的契约:约束在编译期发现程序的错误
链接地址:https://www.777doc.com/doc-4003201 .html