HarmonyOS7 状态管理全家桶:@State、@Prop、@Link 到底怎么选?
2026/7/23 22:45:34
noexcept是为了解决什么问题?在 C++11 之前,异常说明使用的是动态异常规范:
voidf()throw(int,std::bad_alloc);voidg()throw();// 表示不抛异常unexpected(),再terminate()几乎没人敢用
noexcept的核心动机是:
让“是否会抛异常”成为一个可在编译期推导、可用于优化、可影响接口选择的属性
换句话说:
异常是否发生,从「运行期契约」升级为「类型系统的一部分」
noexcept的本质语义(非常重要)voidf()noexcept;并不是说:
“这个函数不会抛异常”
而是说:
如果这个函数抛异常,程序将立刻调用
std::terminate()
即:
try{f();}catch(...){std::terminate();// 无条件}noexcept是承诺,不是能力检测。
noexcept的两种形式noexceptvoidf()noexcept;等价于:
voidf()noexcept(true);noexcept(C++11 核心设计)template<typenameT>voidfoo(T&&x)noexcept(noexcept(T(std::forward<T>(x))));异常规格成为编译期表达式
template<typenameT>Tmake()noexcept(noexcept(T())){returnT();}noexcept是类型系统的一部分voidf()noexcept;voidg();usingF=void(*)();usingNF=void(*)()noexcept;F pf=g;// OKNF pnf=f;// OK但:
NF pnf=g;// 编译错误noexcept是函数类型签名的一部分。
noexcept对性能至关重要?noexcept→完全移除异常元数据在 hot loop / 数值计算 / SLAM 后端中尤为关键。
std::vector扩容行为if(T isnoexcept-move-constructible)使用 moveelse使用 copy等价于:
std::is_nothrow_move_constructible_v<T>noexcept会导致性能灾难structBad{Bad(Bad&&){}// 没有 noexcept};structGood{Good(Good&&)noexcept{}};std::vector<Bad>v1;// 扩容时 copystd::vector<Good>v2;// 扩容时 move这就是 STL 要求 move ctornoexcept的原因
noexcept与移动语义的关系(核心)structX{X(X&&)noexcept=default;X&operator=(X&&)noexcept=default;};vector,deque,map等容器std::optional,std::variantstd::unique_ptr全部依赖noexcept来选择移动路径
noexcept与析构函数(极其重要)~T()noexcept(true);// 默认即:
析构函数隐式
noexcept
~T(){throwstd::runtime_error("boom");}std::terminate()
原因:防止 stack unwinding 二次异常
~T()noexcept{try{cleanup();}catch(...){log_error();}}noexcept与模板元编程std::is_nothrow_move_constructible<T>std::is_nothrow_copy_constructible<T>std::is_nothrow_destructible<T>template<typenameT>voidsafe_swap(T&a,T&b)noexcept(std::is_nothrow_move_constructible_v<T>&&std::is_nothrow_move_assignable_v<T>){T tmp=std::move(a);a=std::move(b);b=std::move(tmp);}noexceptvsconst| 属性 | 是否属于类型 |
|---|---|
const | 是 |
noexcept | 是 |
throw() | 否(已废弃) |
noexcept= 不会抛异常事实:
noexcept的语义是“一旦抛异常,立即std::terminate()”
#include<iostream>#include<stdexcept>voidf()noexcept{std::cout<<"before throw\n";throwstd::runtime_error("boom");std::cout<<"after throw\n";}intmain(){f();}before throw terminate called after throwing an instance of 'std::runtime_error'catch根本来不及noexceptvoidg(){throwstd::runtime_error("boom");}intmain(){try{g();}catch(conststd::exception&e){std::cout<<"caught: "<<e.what()<<'\n';}}caught: boom正常异常语义
noexcept是“强终止契约”,不是“不会抛”的保证
noexcept这是生产事故级错误
voidmay_throw(){throwstd::runtime_error("error");}voidwrapper()noexcept{may_throw();//}intmain(){wrapper();}terminate called after throwing an instance of 'std::runtime_error'voidlog(conststd::string&s){if(s.empty()){throwstd::logic_error("empty");}}voidfoo()noexcept{log("");// 间接抛异常}根本看不到 throw,却直接 terminate
voidfoo()noexcept{try{log("");}catch(...){// fallback / logging}}noexcepttemplate<typenameF>voidcall(F&&f)noexcept(noexcept(f())){f();}只有当“整个调用链都不抛异常”时,才可以写
noexcept
noexcept这是 STL 性能退化最常见的来源
#include<vector>structBad{Bad()=default;Bad(constBad&)=default;Bad(Bad&&){}// 没有 noexcept};intmain(){std::vector<Bad>v;v.reserve(1);v.emplace_back();v.emplace_back();// 触发扩容}if(is_nothrow_move_constructible<T>)moveelsecopystructGood{Good()=default;Good(constGood&)=default;Good(Good&&)noexcept{}//};structVerbose{Verbose()=default;Verbose(constVerbose&){std::cout<<"copy\n";}Verbose(Verbose&&)noexcept{std::cout<<"move\n";}};std::vector<Verbose>v;v.emplace_back();v.emplace_back();move如果去掉noexcept,输出是:
copy一个没写
noexcept的 move ctor,等价于“禁用移动语义”
| 误区 | 本质错误 |
|---|---|
noexcept= 不会抛 | 实际是“抛了就死” |
随便加noexcept | 违反调用链异常安全 |
move ctor 没noexcept | STL 主动退化到 copy |
noexcept| 场景 |
|---|
| 移动构造 / 移动赋值 |
| 析构函数 |
| swap |
| RAII cleanup |
| 数值内核、实时系统 |
| 场景 |
|---|
| 构造函数(分配内存) |
| IO |
| 用户回调 |
| 场景 |
|---|
| 无法保证内部调用链不抛异常 |
structPose{Eigen::Matrix4d T;Pose()=default;Pose(Pose&&other)noexcept:T(std::move(other.T)){}Pose&operator=(Pose&&other)noexcept{T=std::move(other.T);return*this;}~Pose()noexcept=default;};这类类型在SLAM 后端、图优化、点云容器中是黄金标准
noexcept不是语法糖,而是现代 C++ 性能、异常安全和库设计的核心支点