当前位置: 首页 > news >正文

C++26 函数契约(Contract)概览

文章目录

    • 1. 什么是契约编程?
      • 契约编程的三大核心:
    • 2. C++26 契约编程的语法
      • 语法示例
    • 3. 契约检查模式
      • 3.1. `default` 模式
      • 3.2. `audit` 模式
      • 3.3. `axiom` 模式
      • 检查模式的设置
    • 4. 契约编程与传统 `assert` 的区别
      • 示例对比
    • 5. 契约编程的应用场景
    • 6. 注意事项
    • 7. 示例: 带契约的矩形面积计算
    • 8. 总结

契约编程(Contracts)预计成为 C++26 语言标准的一部分. 这一特性为开发者提供了一种标准化的方式来表达函数的前置条件, 后置条件以及断言, 从而显著提升代码的可读性, 可靠性和可维护性. 在本文中, 我们将深入探讨契约编程的概念, 语法, 检查模式以及实际应用场景, 帮助您快速掌握这一强大的新特性.


1. 什么是契约编程?

契约编程起源于软件工程的一种理念, 最早由 Bertrand Meyer 在 Eiffel 语言中提出. 它的核心思想是将函数的 输入约束(前置条件)输出约束(后置条件) 明确化, 形成一种程序逻辑上的契约. 这种契约不仅有助于描述函数的行为, 还能用于运行时验证, 帮助开发者快速发现问题.

契约编程的三大核心:

  1. 前置条件(Preconditions):
    函数执行前必须满足的条件, 由调用者负责. 例如, 输入参数是否有效.

  2. 后置条件(Postconditions):
    函数执行完成后必须满足的条件, 由实现者负责. 例如, 返回值是否符合预期.

  3. 断言(Assertions):
    程序执行过程中必须满足的逻辑条件, 用于验证程序内部状态是否正确.


2. C++26 契约编程的语法

C++26 提供了三个新的属性标记, 专门用于定义契约:

  • [[pre: ...]]: 定义前置条件.
  • [[post: ...]]: 定义后置条件.
  • [[assert: ...]]: 定义断言.

语法示例

以下是一个简单的除法函数, 展示了契约编程的基本用法:

#include <iostream>int divide(int a, int b)[[pre:b != 0]]                   // 前置条件: 除数不能为零[[post result:result == a / b]]  // 后置条件: 返回值必须等于 a / b
{return a / b;
}int main() {divide(10, 0);  // 触发前置条件失败, 运行时终止return 0;
}

输出:

Program returned: 139
contract violation in function divide at /app/example.cpp:3: b != 0
terminate called without an active exception
Program terminated with signal: SIGSEGV

在 Compiler Explorer 中查看


3. 契约检查模式

契约编程不仅仅是简单的运行时检查, 它通过 检查模式 提供了灵活的验证方式. C++26 提供了三种检查模式:

3.1. default 模式

  • 默认模式, 用于开发阶段.
  • 对所有契约条件进行验证, 如果检查失败, 程序终止并报告错误.
  • 适合日常开发和调试.

3.2. audit 模式

  • 加强模式, 用于深度检查.
  • 包括性能敏感路径中的契约条件.
  • 性能开销较高, 适合可靠性要求高的复杂场景.

3.3. axiom 模式

  • 假设模式, 用于生产环境.
  • 假定所有契约条件始终成立, 不进行运行时检查.
  • 编译器可以利用这些契约条件优化代码, 例如移除不必要的分支.

检查模式的设置

可以通过编译器选项控制契约检查模式, 例如:

  • GCC 示例
    g++ -std=c++26 -fcontracts -fcontract-build-level=default main.cpp   # 使用 default 模式
    g++ -std=c++26 -fcontracts -fcontract-build-level=audit main.cpp    # 使用 audit 模式
    g++ -std=c++26 -fcontracts -fcontract-build-level=off main.cpp    # 使用 axiom 模式
    

4. 契约编程与传统 assert 的区别

C++26 的契约与传统的 assert 语句在设计目标和功能上有显著差异:

特性契约(Contracts)assert
目标定义函数的行为约定, 明确调用和实现责任.临时检查某些条件是否满足, 主要用于调试.
语法专用关键字: [[pre:]], [[post:]].标准库函数: assert(condition).
范围全局行为约定, 包括前置条件, 后置条件和断言.局部检查, 仅在代码块中验证条件.
运行时模式支持 default, auditaxiom 模式.只有简单的 NDEBUG 开关控制检查启用.

示例对比

契约:

int divide(int a, int b)[[pre: b != 0]]               // 契约描述行为约定
{return a / b;
}

assert:

int divide(int a, int b) {assert(b != 0);               // 仅用于调试阶段的检查return a / b;
}

5. 契约编程的应用场景

  1. 高可靠性系统:

    • 航空航天, 自动驾驶, 金融系统等需要严格保证代码正确性.
    • 契约能够防止运行时出现未定义行为.
  2. 公共 API 开发:

    • 通过契约明确调用者的责任和函数行为, 为用户提供清晰的文档.
  3. 复杂算法实现:

    • 使用契约验证中间结果, 确保算法逻辑正确.
  4. 生产环境优化:

    • 在生产模式下切换到 axiom 模式, 移除所有运行时检查, 提升性能.

6. 注意事项

  1. 运行时开销:

    • defaultaudit 模式会增加运行时检查开销, 在性能敏感场景需谨慎使用.
  2. 编译器支持:

    • C++26 的契约编程尚未被所有主流编译器完全支持, 需要注意工具链的更新情况.
  3. 与异常处理的区别:

    • 契约不用于替代异常处理, 它更注重逻辑验证而非用户友好性.

7. 示例: 带契约的矩形面积计算

以下代码展示如何为类方法添加契约:

#include <iostream>struct Rectangle {int width;int height;int area() const[[pre:width > 0 && height > 0]]  // 前置条件: 长和宽必须为正[[post result:result > 0]]       // 后置条件: 面积必须为正{return width * height;}
};int main() {Rectangle rect{5, 10};std::cout << "Area: " << rect.area() << std::endl;Rectangle invalid{-5, 10};std::cout << invalid.area(); // 触发前置条件失败return 0;
}

在 Compiler Explorer 中查看代码

注意在三种不同模式下的输出不尽相同:

  1. default/audit:
    contract violation in function Rectangle::area at /app/example.cpp:7: width > 0 && height > 0
    terminate called without an active exception
    Program terminated with signal: SIGSEGV
    Area: 50
    
  2. axiom:
    Area: 50
    -50
    

8. 总结

契约编程通过前置条件, 后置条件和断言, 为开发者提供了一个全面的工具来提升代码质量. 在开发阶段, 契约编程有助于快速发现问题; 在生产环境中, 通过合理选择检查模式, 可以兼顾性能与安全性.

契约编程不仅是一种语言特性, 更是现代软件开发中提升代码可靠性的重要工具. 随着编译器支持的逐步完善, 它将成为每位 C++ 开发者的得力助手!

相关文章:

C++26 函数契约(Contract)概览

文章目录 1. 什么是契约编程?契约编程的三大核心: 2. C26 契约编程的语法语法示例 3. 契约检查模式3.1. default 模式3.2. audit 模式3.3. axiom 模式检查模式的设置 4. 契约编程与传统 assert 的区别示例对比 5. 契约编程的应用场景6. 注意事项7. 示例: 带契约的矩形面积计算…...

Flink CDC 自定义函数处理 SQLServer XML类型数据 映射 doris json字段方案

Flink CDC 自定义函数处理 SQLServer XML类型数据方案 1. 背景 因业务使用SQLServer数据库&#xff0c;CDC同步到doris 数仓。对于SQLServer xml类型&#xff0c;doris没有相应的字段对应&#xff0c; 可以使用json来存储xml数据。需要进行一步转换。从 flink 自定义函数入手…...

F.interpolate函数

F.interpolate 是 PyTorch 中用于对张量&#xff08;通常是图像数据&#xff09;进行插值操作的函数&#xff0c;常用于调整张量的大小&#xff0c;例如改变图像的分辨率。它支持多种插值方法&#xff0c;包括最近邻插值、双线性插值和三次插值等。 语法 torch.nn.functional…...

华为交换机---自动备份配置到指定ftp/sftp服务器

华为交换机—自动备份配置到指定ftp服务器 需求 交换机配置修改后及时备份相关配置,每次配置变化后需要在1分钟后自动进行保存,并且将配置上传至FTP服务器;每隔30分钟,交换机自动把配置上传到FTP服务器。 1、定时保存新配置的时间间隔为*分钟(1天=1440),默认为30分钟(…...

nginx学习之路-nginx配置https服务器

文章目录 1. 生成证书2. 配置证书1. 拷贝证书文件2. 修改conf/nginx.conf文件内容 3. 查看效果1. 重载配置2. 访问 1. 生成证书 在linux系统下执行&#xff0c;使用openssl命令。&#xff08;windows环境也可以使用cmder&#xff09; # 1. 生成私钥 server2025.key(无密码保护…...

UCAS 24秋网络认证技术 CH10 SSL 复习

TLS字段、参数含义要了解每个消息是什么意思 基本方式只验证服务端&#xff0c;服务端有证书&#xff0c;变形方式加上验证客户端TLS1.3区别 协商过程 背景 Record层使用的各种加密算法参数&#xff0c;均由Handshake协议协商获得。 具体过程 随机数交换 Client/Server相互…...

【linux内核分析-存储】EXT4源码分析之“文件删除”原理【七万字超长合并版】(源码+关键细节分析)

EXT4源码分析之“文件删除”原理【七万字超长合并版】&#xff08;源码关键细节分析&#xff09;&#xff0c;详细的跟踪了ext4文件删除的核心调用链&#xff0c;分析关键函数的细节&#xff0c;解答了开篇中提出的三个核心疑问。 文章目录 提示前言全文重点索引1.源码解析1.1 …...

代码随想录 day62 第十一章 图论part11

第十一章&#xff1a;图论part11 Floyd 算法精讲 Floyd 算法代码很简单&#xff0c;但真正理解起原理 还是需要花点功夫&#xff0c;大家在看代码的时候&#xff0c;会发现 Floyd 的代码很简单&#xff0c;甚至看一眼就背下来了&#xff0c;但我为了讲清楚原理&#xff0c;本…...

springboot571基于协同过滤算法的私人诊所管理系统(论文+源码)_kaic

摘 要 随着时代的发展&#xff0c;人们的生活方式得到巨大的改变&#xff0c;从而慢慢地出现了大量私人诊所信息&#xff0c;私人诊所信息管理需要一个现代化的管理系统&#xff0c;进行私人诊所的管理。 私人诊所管理系统的开发就是为了解决私人诊所信息管理的问题&#xff0…...

Uniapp Android 本地离线打包(详细流程)

一、简介 App 离线 SDK 暂时不支持 Kotlin&#xff0c;未来不清楚。 uniapp 提供了 云打包 与 本地打包 两种方案&#xff0c;云打包 需要排队且还有次数限制&#xff0c;本地打包 则就没有这些限制&#xff0c;而且会 本地打包 对开发 原生插件 有很大的帮助。 细节&#x…...

vite+vue3动态引入资源文件(问题已解决但离了个大谱)

教程很详细&#xff0c;直接上代码 解决方法&#xff08;赶时间的小友理解下这函数就能解决问题了&#xff0c;就是处理了下路径&#xff0c;运气不好遇到问题再回来也不迟&#x1f923;&#x1f923;&#x1f923;&#xff09; const getSvgUrl (name) > {// name: svg_1…...

通过 4 种方式快速将音乐从 iPod 传输到 Android

概括 在 iPod 上听音乐很酷&#xff0c;但是当您拥有最新的 Android 手机时&#xff0c;也许您想在新手机上欣赏 iPod 音乐。那么&#xff0c;你的计划是什么&#xff1f;如何将音乐从 iPod 传输到 Android&#xff1f; 如果您担心这个问题&#xff0c;请看看下面的方法。他们…...

ArcGIS中怎么把数据提取到指定范围(裁剪、掩膜提取)

最近&#xff0c;经常能收到怎么把数据提取到指定范围、栅格数据怎么裁剪、矢量数据怎么裁剪、栅格数据怎么掩膜提取的咨询。 下面是我对这个问题的解决思路&#xff1a; 对于矢量数据&#xff1a; ①首先把数据加载进来 ②软件界面上面的工具栏找到→地理处理→裁剪&#x…...

【Vaadin flow 实战】第3讲-快速上手构建VaadinFlow+Springboot的全栈web项目

快速构建VaadinFlowSpringboot的全栈web项目 温馨提示&#xff0c;本文讲解比较精炼&#xff0c;主要以快速上手开发为主。 官方提供了与本文类似的教程讲解&#xff0c;地址https://vaadin.com/docs/latest/getting-started 1访问vaadin官方提供的start网站(类似于 spring i…...

HBase Cassandra的部署和操作

目录 一&#xff0e;数据库的部署与配置 二&#xff0e;使用命令访问数据库 三&#xff0e;数据库的设计 四&#xff0e;编程实现数据库的访问 一&#xff0e;数据库的部署与配置 1.在单个节点上对进行数据库的单机部署 &#xff08;1&#xff09;下载apache-cassandra-4.1.7-…...

用户界面软件01

Jens Coldewey 著&#xff0c;Tom.X 译 本文中的模式语言逐步深入地探讨用户界面架构的设计&#xff0c;它基于人机工程学&#xff0c;足以形成一套完整的体系。如果你对这方面有兴趣&#xff0c;请参考[Tog92]&#xff0c;[Coo95]和[Col95]。 本文不讨论用户界面的布局&…...

【云原生】Docker Compose 从入门到实战使用详解

目录 一、前言 二、Docker Compose 介绍 2.1 Docker Compose概述 2.2 Docker Compose特点 2.3 Docker Compose使用场景 三、Docker Compose 安装 3.1 安装docker环境 3.2 Docker Compose安装方式一 3.2.1 下载最新版 3.2.2 设置权限 3.2.3 设置软链接 3.2.4 查看版本…...

【ShuQiHere】使用 SCP 进行安全文件传输

【ShuQiHere】&#x1f680; 在日常的开发和运维工作中&#xff0c;文件传输是一个常见的任务。scp&#xff08;Secure Copy&#xff09;是一个基于 SSH 协议的文件传输工具&#xff0c;能够在本地和远程主机之间安全地复制文件和目录。本文将详细介绍 scp 的使用方法&#xf…...

海康威视H5player问题汇总大全

由于除了要支持Windows平台&#xff0c;还要支持国产系统的平台&#xff0c;这时就用到了H5player&#xff0c;但是这个在使用调试的时候会遇到各种各样的问题&#xff0c;便在此分享一下&#xff0c;供大家分享&#xff01;&#xff01;&#xff01; 问题一&#xff1a;Unexp…...

力扣23.合并K个升序链表

文章目录 一、前言二、最小堆解法三、分治解法 一、前言 23. 合并 K 个升序链表 本题的要求是把K个链表进行合并&#xff0c;合并后的链表必须是从小到大的。 并且这K个链表也是从小到大的升序链表。 二、最小堆解法 既然每个链表都是升序的&#xff0c;也就是从小到大的。 …...

【位运算】消失的两个数字(hard)

消失的两个数字&#xff08;hard&#xff09; 题⽬描述&#xff1a;解法&#xff08;位运算&#xff09;&#xff1a;Java 算法代码&#xff1a;更简便代码 题⽬链接&#xff1a;⾯试题 17.19. 消失的两个数字 题⽬描述&#xff1a; 给定⼀个数组&#xff0c;包含从 1 到 N 所有…...

Qt Widget类解析与代码注释

#include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this); }Widget::~Widget() {delete ui; }//解释这串代码&#xff0c;写上注释 当然可以&#xff01;这段代码是 Qt …...

Objective-C常用命名规范总结

【OC】常用命名规范总结 文章目录 【OC】常用命名规范总结1.类名&#xff08;Class Name)2.协议名&#xff08;Protocol Name)3.方法名&#xff08;Method Name)4.属性名&#xff08;Property Name&#xff09;5.局部变量/实例变量&#xff08;Local / Instance Variables&…...

OPenCV CUDA模块图像处理-----对图像执行 均值漂移滤波(Mean Shift Filtering)函数meanShiftFiltering()

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 在 GPU 上对图像执行 均值漂移滤波&#xff08;Mean Shift Filtering&#xff09;&#xff0c;用于图像分割或平滑处理。 该函数将输入图像中的…...

微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据

微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据 Power Query 具有大量专门帮助您清理和准备数据以供分析的功能。 您将了解如何简化复杂模型、更改数据类型、重命名对象和透视数据。 您还将了解如何分析列&#xff0c;以便知晓哪些列包含有价值的数据&#xff0c;…...

k8s从入门到放弃之HPA控制器

k8s从入门到放弃之HPA控制器 Kubernetes中的Horizontal Pod Autoscaler (HPA)控制器是一种用于自动扩展部署、副本集或复制控制器中Pod数量的机制。它可以根据观察到的CPU利用率&#xff08;或其他自定义指标&#xff09;来调整这些对象的规模&#xff0c;从而帮助应用程序在负…...

ZYNQ学习记录FPGA(一)ZYNQ简介

一、知识准备 1.一些术语,缩写和概念&#xff1a; 1&#xff09;ZYNQ全称&#xff1a;ZYNQ7000 All Pgrammable SoC 2&#xff09;SoC:system on chips(片上系统)&#xff0c;对比集成电路的SoB&#xff08;system on board&#xff09; 3&#xff09;ARM&#xff1a;处理器…...

32单片机——基本定时器

STM32F103有众多的定时器&#xff0c;其中包括2个基本定时器&#xff08;TIM6和TIM7&#xff09;、4个通用定时器&#xff08;TIM2~TIM5&#xff09;、2个高级控制定时器&#xff08;TIM1和TIM8&#xff09;&#xff0c;这些定时器彼此完全独立&#xff0c;不共享任何资源 1、定…...

算法—栈系列

一&#xff1a;删除字符串中的所有相邻重复项 class Solution { public:string removeDuplicates(string s) {stack<char> st;for(int i 0; i < s.size(); i){char target s[i];if(!st.empty() && target st.top())st.pop();elsest.push(s[i]);}string ret…...

Linux操作系统共享Windows操作系统的文件

目录 一、共享文件 二、挂载 一、共享文件 点击虚拟机选项-设置 点击选项&#xff0c;设置文件夹共享为总是启用&#xff0c;点击添加&#xff0c;可添加需要共享的文件夹 查询是否共享成功 ls /mnt/hgfs 如果显示Download&#xff08;这是我共享的文件夹&#xff09;&…...