C++安全编码:断言

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/uestcyms/article/details/88356407

断言

简介

在程序设计中,断言(assertion)是一种放在程序中的一阶逻辑(如一个结果为真或是假的逻辑判断式),目的是为了标示与验证程序开发者预期的结果-当程序运行到断言的位置时,对应的断言应该为真。若断言不为真时,程序会中止运行,并给出错误消息。

C++断言包含运行期检查断言、静态断言

  • 运行期检查的断言
    在程序运行时,可以用断言检查程序开发时的假设,确认这些假设是否成立。
    存在先天的缺点:可能有改变存储器数据或是线程时序的风险,因此需小心的处理断言,确认断言在程序中没有其他的副作用。
  • 静态断言(c++11以上,static_assert)
    只在编译期间检查的断言称为静态断言,静态断言必需配合清楚的注解说明。
    介绍static_assert

程序结构中的断言有助于在不使用第三方程式库的情形下,应用测试驱动开发的开发方式。

示例

运行时期检查的断言

  • 头文件:
所需引用头文件 基本用法
assert.h(C语法)、cassert(C++) assert(bool_constexpr)

assert.h与cassert : 简而言之,#include<assert.h>是c语言引用库的写法,C++为了兼容C语言也可以这么写,但是可能缺少C++库的某些特性(比如c99中中的assert.h没有static_assert宏,C++14的cassert中包含);编写C++代码时,最好还是选择#include 的写法。

规则 详细
规则一 断言必须使用宏定义,禁止直接调用系统提供的assert()
规则二 运行时可能会导致的错误,严禁使用断言
规则三 严禁在断言内改变运行环境
规则四 不要将多条语句放在同一个断言中(无法知道到底是哪个条件出错)

规则二详细说明:
环境等外界因素导致的错误,不能使用断言进行判断;断言属于契约式设计中的前置条件,任何断言失败,一定标识着某处代码的错误,需要更改代码,类比编译错误;
如果代码书写完全正确,但因外界环境或者用户操作仍然可能发生的事件,都不适合用断言;请使用条件判断或异常进行处理。
错误示例:

FILE *fp = fopen(path,"r");
ASSERT(fp != NULL); //文件有可能打开失败

断言使用示例:
包含头文件assert_self.h、main.cpp

/**********************************************************************
      >File Name:     assert_self.h
      >Author:        sunrise
      >Mail:          [email protected]
      >Created Time:  Fri 08 Mar 2019 04:52:55 AM EST
*************************************************************/

#include<iostream>
#include<cassert>
using namespace std;
#ifndef ASSERT_SELF_H
#define ASSERT_SELF_H

#ifdef DEBUG // 定义宏变量,来控制程序是否打开断言
#define ASSERT(f) assert(f)
#else
#define ASSERT(f) ((void)0)
#endif

#endif

/**********************************************************************
      >File Name:     main.cpp
      >Author:        sunrise
      >Mail:          [email protected]
      >Created Time:  Fri 08 Mar 2019 04:56:03 AM EST
*************************************************************/

#include<iostream>
#include "assert_self.h"
using namespace std;

int main()
{
    int i = 1;
    ASSERT(i > 2);
    cout << "success !!!" << endl;
    return 0;
}

通过宏在编译阶段进行控制(规则一)
打开ASSERT宏:
编译命令(使用-D 定义宏):

g++ main.cpp assert_self.h --std=c++11 -D DEBUG -o assert

执行结果,断言生效:

assert: main.cpp:15: int main(): Assertion `i > 2’ failed.
Aborted (core dumped)

关闭ASSERT宏,正常编译即可
编译命令:

g++ main.cpp assert_self.h --std=c++11 -o assert

执行结果:

success !!!

静态断言

C11 (程序标准版本)及C++11可以用static_assert支持静态断言。

示例:

/**********************************************************************
      >File Name:     test.cpp
      >Author:        sunrise
      >Mail:          [email protected]
      >Created Time:  Fri 08 Mar 2019 03:15:51 AM EST
*************************************************************/

#include<iostream>
using namespace std;

#include <type_traits>

template <class T>
void swap1(T& a, T& b)
{
    static_assert(std::is_copy_constructible<T>::value,"Swap requires copying");
    static_assert(std::is_nothrow_copy_constructible<T>::value
                && std::is_nothrow_copy_assignable<T>::value,
                "Swap requires nothrow copy/assign");
    auto c = b;
    b = a;
    a = c;
}

template <class T>
struct data_structure
{
    static_assert(std::is_default_constructible<T>::value,
                "Data Structure requires default-constructible elements");
};

struct no_copy
{
    no_copy ( const no_copy& ) = delete;
    no_copy () = default;
};

struct no_default
{
    no_default () = delete;
};

int main()
{
    const int i = 2;
    static_assert(i > 3,"i should large than 3");

    int a, b;
    swap1(a, b);

    no_copy nc_a, nc_b;
    //swap1(nc_a, nc_b); // 1

    data_structure<int> ds_ok;
    data_structure<no_default> ds_error; // 2
    return 0;
}

备注:std::is_copy_constructible::value这些函数是库函数,判断函数构造函数

编译命令:

g++ test.cpp --std=c++11 -o test

执行结果:

test.cpp: In function ‘int main()’:
test.cpp:47:5: error: static assertion failed: i should large than 3
     static_assert(i > 3,"i should large than 3");
     ^
test.cpp: In instantiation of ‘struct data_structure<no_default>’:
test.cpp:55:32:   required from here
test.cpp:29:5: error: static assertion failed: Data Structure requires default-constructible elements
     static_assert(std::is_default_constructible<T>::value,
     ^

猜你喜欢

转载自blog.csdn.net/uestcyms/article/details/88356407