【UE5 C++课程系列笔记】15——Assert的基本使用
目录
概念
一、Check
二、Verify
三、Ensure
对比
基本使用
一、check的基本使用
二、ensure的基本使用
三、verify的基本使用
概念
assert
可在开发期间帮助检测和诊断不正常或无效的运行时条件。这些条件通常检查是否指针为非空、除数为非零、函数并非递归运行,或代码要求的其他重要假设。但每次检查会使得效率十分低下。某些情况下,assert
会在延迟崩溃发生之前发现导致该崩溃的bug,例如删除未来tick所需的对象,协助开发人员发现引起崩溃的根本原因。assert
的关键特性之一是不存在于发布代码中,这意味着不但不会影响发布产品的性能,也没有任何副作用。对 assert
最简单的理解就是:"断言"必须一律为true,否则程序会停止运行。
虚幻引擎提供 assert
等同项的三个不同族系:check
、verify
和 ensure
。若要检查这些功能背后的代码,可在 Engine/Source/Runtime/Core/Public/Misc/AssertionMacros.h
中找到相关的宏。各个功能的行为略有不同,但它们都是开发期间使用的诊断工具,目标大致相同。
一、Check
Check族系最接近基础 assert
,因为当第一个参数得出的值为false时,此族系的成员会停止执行,且默认不会在发布版本中运行。以下Check宏可用:
宏 | 参数 | 行为 |
---|---|---|
check 或 checkSlow | Expression | 若 Expression 为false,停止执行 |
checkf 或 checkfSlow | Expression 、FormattedText 、... | 若 Expression 为false,则停止执行并将 FormattedText 输出到日志 |
checkCode | Code | 在运行一次的do-while循环结构中执行 Code ;主要用于准备另一个Check所需的信息 |
checkNoEntry | (无) | 若此行被hit,则停止执行,类似于 check(false) ,但主要用于应不可到达的代码路径 |
checkNoReentry | (无) | 若此行被hit超过一次,则停止执行 |
checkNoRecursion | (无) | 若此行被hit超过一次而未离开作用域,则停止执行 |
unimplemented | (无) | 若此行被hit,则停止执行,类似于 check(false) ,但主要用于应被覆盖而不会被调用的虚拟函数 |
Check宏在调试(Debug)、开发(Development)、测试(Test)和发布编辑器(Shipping Editor)版本中运行(以"Slow"结尾的宏除外,其仅在调试(Debug)版本中运行)。定义 USE_CHECKS_IN_SHIPPING
以保留一个true值(通常为 1
),使Check宏可在所有版本中运行。此法在以下情况中十分实用:怀疑Check宏中的代码正在修改值;发现了仅存在于在发布版本中且难以追踪的bug,但认为现有Check宏能找到这些bug。项目发布时应将 USE_CHECKS_IN_SHIPPING
设为默认值 0
。
二、Verify
在大部分版本中,Verify族系的行为与Check族系相同。但即便在禁用Check宏的版本中,Verify宏也会计算其表达式的值。这意味着仅当该表达式需要独立于诊断检查之外运行时,才应使用Verify宏。举例而言,若某个函数执行操作,然后返回 bool
来说明该操作是否成功,则应使用Verify而非Check来确保该操作成功。因为在发布版本中Verify将忽略返回值,但仍将执行操作。而Check在发布版本中根本不调用该函数,所以行为才会有所不同。
宏 | 参数 | 行为 |
---|---|---|
verify 或 verifySlow | Expression | 若 Expression 为false,停止执行 |
verify 或 verifyfSlow | Expression 、FormattedText 、... | 若 Expression 为false,则停止执行并将 FormattedText 输出到日志 |
Verify宏在调试(Debug)、开发(Development)、测试(Test)和发布编辑器(Shipping Editor)版本中完整运行(以"Slow"结尾的宏除外,其仅在调试(Debug)版本中运行)。定义 USE_CHECKS_IN_SHIPPING
来保留一个true值(通常为 1
),从而覆盖此行为。在所有其他情况下,Verify宏将计算其表达式,但不会停止执行或将文本输出到日志。
三、Ensure
Ensure族系类似于Verify族系,但可在出现非致命错误时使用。这意味着,若Ensure宏的表达式计算得出的值为false,引擎将通知崩溃报告器,但仍会继续运行。为避免崩溃报告器收到太多通知,Ensure宏在每次引擎或编辑器会话中仅报告一次。若实际情况需要Ensure宏在每次表达式计算得值为false时都报告一次,则使用"Always"版本的宏。
宏 | 参数 | 行为 |
---|---|---|
ensure | Expression | Expression 首次为false时通知崩溃报告器 |
ensureMsgf | Expression 、FormattedText 、... | Expression 首次为false时通知崩溃报告器并将 FormattedText 输出到日志 |
ensureAlways | Expression | Expression 为false时通知崩溃报告器 |
ensureAlwaysMsgf | Expression , FormattedText , ... | Expression 为false时通知崩溃报告器并将 FormattedText 输出到日志 |
Ensure宏在所有版本中计算其表达式的值,但仅在调试(Debug)、开发(Development)、测试(Test)和发布编辑器(Shipping Editor)版本中联系崩溃报告器。
对比
宏名称 | 调试版本行为 | 发行版本行为 | 侧重点及适用场景 |
---|---|---|---|
check | 条件为 false 时触发断言失败,程序暂停,输出详细错误信息,方便开发者定位问题 | 通常被移除,不进行条件检查,不影响最终产品性能 | 主要用于开发调试阶段,验证代码逻辑假设条件,查找潜在的代码错误 |
verify | 同 check ,条件为 false 时触发断言失败,程序暂停,输出错误信息 | 保留条件检查,触发断言失败后处理方式与调试版本不同(通常不会暂停程序),需开发者提前规划错误处理机制 | 侧重于对关键条件在发行版本中也进行持续监控,保障游戏稳定性,适用于如资源加载、关键配置参数验证等重要情况 |
ensure | 条件为 false 时触发断言失败,尝试采取相对 “温和” 的措施处理错误,如提示信息、尝试恢复操作等,程序不一定暂停 | 类似调试版本,会尝试采取合适的措施应对错误情况,注重用户体验和游戏的可恢复性 | 从用户体验和程序健壮性角度出发,适用于可能出现异常但希望游戏尽量 “容错” 继续运行的情况,如网络通信、外部设备连接等易受影响的功能模块相关验证 |
基本使用
一、check的基本使用
1. 新建一个Actor类,这里命名为“AssertActor”。在“AssertActor.h”中定义一个名为“AttackEnemey”的方法,传入一个Actor类型的引用
再定义一个属性值
在“AssertActor.cpp”中实现“AttackEnemey”函数
2. 创建派生自“AssertActor”的蓝图类“BP_AssertActor”
将“BP_AssertActor”拖入视口
3. 在关卡蓝图中通过按键调用“AttackEnemey”函数
如果“AttackEnemey”函数传入了一个空指针,如下图。此时调用“AttackEnemey”函数,编辑器会崩溃
二、ensure的基本使用
在“AssertActor”中新实现一个“AttackEnemey2”函数,如下图。这里使用“ensure”
在关卡蓝图中通过1键调用“AttackEnemy2”函数
运行后,按下1键,可以看到虽然还是会报错,但是当Continue后编辑器并不会崩溃
三、verify的基本使用
在“AssertActor”中定义修改法力值的函数“ModifyMana”,定义验证法力值的函数“VerifyMana”,设置法力值“Mana”初始大小为50
实现函数“ModifyMana”和“VerifyMana”如下。每次调用“ModifyMana”时将法力值减20。每次调用“VerifyMana”时先调用“ModifyMana”,然后判断“ModifyMana”的返回结果是否大于0
在关卡蓝图中调用“VerifyMana”
调用3次“VerifyMana”后会出现如下错误,但是Continue后还是可以继续执行后续逻辑,不会造成编辑器崩溃。
“AssertActor”完整代码:
// Fill out your copyright notice in the Description page of Project Settings.#pragma once#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "AssertActor.generated.h"UCLASS()
class STUDY_API AAssertActor : public AActor
{GENERATED_BODY()public: // Sets default values for this actor's propertiesAAssertActor();UFUNCTION(BlueprintCallable)void AttackEnemey(AActor* InActor);UFUNCTION(BlueprintCallable)void AttackEnemey2(AActor* InActor);UFUNCTION(BlueprintCallable)void VerifyMana();protected:// Called when the game starts or when spawnedvirtual void BeginPlay() override;int32 ModifyMana();public: // Called every framevirtual void Tick(float DeltaTime) override;protected:int32 Health = 100;int32 Mana = 50;
};
// Fill out your copyright notice in the Description page of Project Settings.#include "Assert/AssertActor.h"// Sets default values
AAssertActor::AAssertActor()
{// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.PrimaryActorTick.bCanEverTick = true;}void AAssertActor::AttackEnemey(AActor* InActor)
{check(InActor != nullptr);AAssertActor* MyAssertActor = CastChecked<AAssertActor>(InActor);MyAssertActor->Health -= 10;
}void AAssertActor::AttackEnemey2(AActor* InActor)
{ensure(InActor != nullptr);AAssertActor* MyAssertActor = Cast<AAssertActor>(InActor);if (MyAssertActor){MyAssertActor->Health -= 10;}else{UE_LOG(LogTemp, Error, TEXT("转型失败了!!!"))}
}void AAssertActor::VerifyMana()
{verify(ModifyMana() > 0);
}// Called when the game starts or when spawned
void AAssertActor::BeginPlay()
{Super::BeginPlay();
}int32 AAssertActor::ModifyMana()
{Mana -= 20;return Mana;
}// Called every frame
void AAssertActor::Tick(float DeltaTime)
{Super::Tick(DeltaTime);
}
官方文档地址:
https://dev.epicgames.com/documentation/zh-cn/unreal-engine/asserts-in-unreal-engine?application_version=5.3
相关文章:

【UE5 C++课程系列笔记】15——Assert的基本使用
目录 概念 一、Check 二、Verify 三、Ensure 对比 基本使用 一、check的基本使用 二、ensure的基本使用 三、verify的基本使用 概念 assert 可在开发期间帮助检测和诊断不正常或无效的运行时条件。这些条件通常检查是否指针为非空、除数为非零、函数并非递归运行&…...

kubernetes Gateway API-1-部署和基础配置
文章目录 1 部署2 最简单的 Gateway3 基于主机名和请求头4 重定向 Redirects4.1 HTTP-to-HTTPS 重定向4.2 路径重定向4.2.1 ReplaceFullPath 替换完整路径4.2.2 ReplacePrefixMatch 替换路径前缀5 重写 Rewrites5.1 重写 主机名5.2 重写 路径5.2.1 重新完整路径5.2.1 重新部分路…...

likeAdmin架构部署(踩坑后的部署流程
1、gitee下载 https://gitee.com/likeadmin/likeadmin_java.git 自己克隆 2、项目注意 Maven:>3.8 ❤️.9 (最好不要3.9已经试过失败 node :node14 (不能是18 已经测试过包打不上去使用14的换源即可 JDK:JDK8 node 需要换源 npm c…...

【一款超好用的开源笔记Logseq本地Docker部署与远程使用指南】
💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…...
浅谈torch.utils.data.TensorDataset和torch.utils.data.DataLoader
1.torch.utils.data.TensorDataset 功能定位 torch.utils.data.TensorDataset 是一个将多个张量(Tensor)数据进行简单包装整合的数据集类,它主要的作用是将相关联的数据(比如特征数据和对应的标签数据等)组合在一起&…...

gesp(C++二级)(16)洛谷:B4037:[GESP202409 二级] 小杨的 N 字矩阵
gesp(C++二级)(16)洛谷:B4037:[GESP202409 二级] 小杨的 N 字矩阵 题目描述 小杨想要构造一个 m m m \times m m...

FFmpeg:详细安装教程与环境配置指南
FFmpeg 部署完整教程 在本篇博客中,我们将详细介绍如何下载并安装 FFmpeg,并将其添加到系统的环境变量中,以便在终端或命令行工具中直接调用。无论你是新手还是有一定基础的用户,这篇教程都能帮助你轻松完成 FFmpeg 的部署。 一、…...
《特征工程:自动化浪潮下的坚守与变革》
在机器学习的广阔天地中,特征工程一直占据着举足轻重的地位。它宛如一位幕后的工匠,精心雕琢着原始数据,将其转化为能够被机器学习模型高效利用的特征,从而推动模型性能迈向新的高度。然而,随着技术的飞速发展…...

webrtc 源码阅读 make_ref_counted模板函数用法
目录 1. 模板参数解析 1.1 typename T 1.2 typename... Args 1.3 typename std::enable_if::value, T>::type* nullptr 2. scoped_refptr 3. new RefCountedObject(std::forward(args)...); 4. 综合说明 5.在webrtc中的用法 5.1 peerConnectionFactory对象的构建过…...
【深度学习基础之多尺度特征提取】特征金字塔(Feature Pyramid)是如何在深度学习网络中提取多尺度特征的?附代码
【深度学习基础之多尺度特征提取】特征金字塔(Feature Pyramid)是如何在深度学习网络中提取多尺度特征的?附代码 【深度学习基础之多尺度特征提取】特征金字塔(Feature Pyramid)是如何在深度学习网络中提取多尺度特征…...
【Docker】离线安装 Docker
离线安装 Docker 在CentOS系统上安装Docker 1、下载 Docker 仓库文件 https://download.docker.com/linux/centos/docker-ce.repo 2、添加 Docker 仓库文件 将上一步下载的文件,移动到 /etc/yum.repos.d/ 目录 3、清除 YUM 缓存 sudo yum clean all sudo yum…...

三大行业案例:AI大模型+Agent实践全景
本文将从AI Agent和大模型的发展背景切入,结合51Talk、哈啰出行以及B站三个各具特色的行业案例,带你一窥事件驱动架构、RAG技术、人机协作流程,以及一整套行之有效的实操方法。具体包含内容有:51Talk如何让智能客服“主动进攻”&a…...

Dockerfile基础指令
1.FROM 基于基准镜像(建议使用官方提供的镜像作为基准镜像,相对安全一些) 举例: 制作基准镜像(基于centos:lastest) FROM cenots 不依赖于任何基准镜像 FROM scratch 依赖于9.0.22版本的tomcat镜像 FROM…...

12.30 linux 文件操作,磁盘分区挂载
ubuntu 在linux 对文件的相关操作【压缩,打包,软链接,文件权限】【head,tail,管道符,通配符,find,grep,cut等】脑图-CSDN博客 1.文件操作 在家目录下创建目录文件&#…...
[图形渲染]【Unity Shader】【游戏开发】 Shader数学基础17-法线变换基础与应用
在计算机图形学中,法线(normal) 是表示表面方向的向量。它在光照、阴影、碰撞检测等领域有着重要作用。本文将介绍如何在模型变换过程中正确变换法线,确保其在光照计算中的正确性,特别是法线与顶点的变换问题。 1. 法线与切线的基本概念 法线(Normal Vector) 法线(或…...
YOLOv9-0.1部分代码阅读笔记-train.py
train.py train.py 目录 train.py 1.所需的库和模块 2.def train(hyp, opt, device, callbacks): 3.def parse_opt(knownFalse): 4.def main(opt, callbacksCallbacks()): 5.def run(**kwargs): 6.if __name__ "__main__": 1.所需的库和模块 import …...
等保测评和密评的相关性和区别
等保测评和密评在网络安全领域均扮演着至关重要的角色,它们之间既存在相关性,又各具特色。 以下是对两者相关性和区别的详细阐述:相关性 1.法律基础:等保测评和密评都是依据国家相关法律法规开展的活动。 等保测评主要依据《网…...

活动预告 |【Part2】 Azure 在线技术公开课:迁移和保护 Windows Server 和 SQL Server 工作负载
课程介绍 通过 Microsoft Learn 免费参加 Microsoft Azure 在线技术公开课,掌握创造新机遇所需的技能,加快对 Microsoft 云技术的了解。参加我们举办的“迁移和保护 Windows Server 和 SQL Server 工作负载”活动,了解 Azure 如何为将工作负载…...
大语言模型(LLM)一般训练过程
大语言模型(LLM)一般训练过程 数据收集与预处理 收集:从多种来源收集海量文本数据,如互联网的新闻文章、博客、论坛,以及书籍、学术论文、社交媒体等,以涵盖丰富的语言表达和知识领域。例如,训练一个通用型的LLM时,可能会收集数十亿甚至上百亿字的文本数据.清洗:去除…...
单片机的基本组成
单片机,即单芯片微型计算机(Single-Chip Microcomputer),是一种将中央处理器(CPU)、内存、输入输出接口等功能集成在一块集成电路芯片上的微型计算机。它具有体积小、成本低、可靠性高、功耗低等优点,在现代电子产品中…...

AI-调查研究-01-正念冥想有用吗?对健康的影响及科学指南
点一下关注吧!!!非常感谢!!持续更新!!! 🚀 AI篇持续更新中!(长期更新) 目前2025年06月05日更新到: AI炼丹日志-28 - Aud…...
云原生核心技术 (7/12): K8s 核心概念白话解读(上):Pod 和 Deployment 究竟是什么?
大家好,欢迎来到《云原生核心技术》系列的第七篇! 在上一篇,我们成功地使用 Minikube 或 kind 在自己的电脑上搭建起了一个迷你但功能完备的 Kubernetes 集群。现在,我们就像一个拥有了一块崭新数字土地的农场主,是时…...

地震勘探——干扰波识别、井中地震时距曲线特点
目录 干扰波识别反射波地震勘探的干扰波 井中地震时距曲线特点 干扰波识别 有效波:可以用来解决所提出的地质任务的波;干扰波:所有妨碍辨认、追踪有效波的其他波。 地震勘探中,有效波和干扰波是相对的。例如,在反射波…...

调用支付宝接口响应40004 SYSTEM_ERROR问题排查
在对接支付宝API的时候,遇到了一些问题,记录一下排查过程。 Body:{"datadigital_fincloud_generalsaas_face_certify_initialize_response":{"msg":"Business Failed","code":"40004","sub_msg…...
DeepSeek 赋能智慧能源:微电网优化调度的智能革新路径
目录 一、智慧能源微电网优化调度概述1.1 智慧能源微电网概念1.2 优化调度的重要性1.3 目前面临的挑战 二、DeepSeek 技术探秘2.1 DeepSeek 技术原理2.2 DeepSeek 独特优势2.3 DeepSeek 在 AI 领域地位 三、DeepSeek 在微电网优化调度中的应用剖析3.1 数据处理与分析3.2 预测与…...
Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以?
Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以? 在 Golang 的面试中,map 类型的使用是一个常见的考点,其中对 key 类型的合法性 是一道常被提及的基础却很容易被忽视的问题。本文将带你深入理解 Golang 中…...

BCS 2025|百度副总裁陈洋:智能体在安全领域的应用实践
6月5日,2025全球数字经济大会数字安全主论坛暨北京网络安全大会在国家会议中心隆重开幕。百度副总裁陈洋受邀出席,并作《智能体在安全领域的应用实践》主题演讲,分享了在智能体在安全领域的突破性实践。他指出,百度通过将安全能力…...

《基于Apache Flink的流处理》笔记
思维导图 1-3 章 4-7章 8-11 章 参考资料 源码: https://github.com/streaming-with-flink 博客 https://flink.apache.org/bloghttps://www.ververica.com/blog 聚会及会议 https://flink-forward.orghttps://www.meetup.com/topics/apache-flink https://n…...

关键领域软件测试的突围之路:如何破解安全与效率的平衡难题
在数字化浪潮席卷全球的今天,软件系统已成为国家关键领域的核心战斗力。不同于普通商业软件,这些承载着国家安全使命的软件系统面临着前所未有的质量挑战——如何在确保绝对安全的前提下,实现高效测试与快速迭代?这一命题正考验着…...

算法笔记2
1.字符串拼接最好用StringBuilder,不用String 2.创建List<>类型的数组并创建内存 List arr[] new ArrayList[26]; Arrays.setAll(arr, i -> new ArrayList<>()); 3.去掉首尾空格...