c++ noexcept与constexpr解析
1. noexcept无需抛出异常
在C++中使用noexcept来标识一个函数不会抛出异常。
noexcept:noexcept默认为true的形式,即抛出异常。
void f() noexcept; // 不会抛出异常 void (*fp)() noexcept(false); //false,抛出异常
要尽量使用noexcept而不是throw。
throw抛出异常:
int m_div(int a,int b)throw(...) //throw表示接收任何类型的异常 { if (b==0) { throw(1); //除数为零,则操作非法,抛出异常 } return a/b; }
noexcept抛出异常:
int m_div(int a,int b)noexcept(false) //允许抛出异常 { if (b==0) { throw(1); //除数为零,则操作非法,抛出异常 } return a/b; }
2. constexpr静态编译关键字
constexpr所表示的是它所声明的变量或者函数,都在静态编译时就已经完成。
程序的运行过程: 编译 ---- 链接 ---- 执行
使用constexpr表示在编译阶段编译器就已经知道了这个变量或者函数的值。
编译期常量
在我们定义数组的时候:给一个变量当作数组的大小是错误的,因为这是一个变量,不是一个常量表达式,数组只接收常量表达式作为初始大小。
int arr1[5]={1,2,3,4,5}; //ok int a=10; int arr2[a]={1,2,3....} //error
使用constexpr:constexpr修饰此变量为一个常量表达式,即a在编译时就已经确定了,因此他是一个编译期常量,可以当作数组的大小。
constexpr int a=10; int arr[a]={1,2,3,4,5....} //ok !
从函数返回常量表达式:返回值是一个常量表达式,可以用作指定数组的大小。
constexpr int func(int a) { return 1+2+a; } ... int arr[func(2)]={1,2,3,4,5}; //ok !
扩展:static_assert表示静态断言,用于确定在编译时就确定的变量的值是否正确。
如果正确,返回true ,什么都不做;错误,则返回false,显示静态断言失败。
constexpr int a=10; static_assert(a==10,"error"); // 正确,什么都不做 static_assert(func(2)==6,"error"); //错误,显示第二个字符串的内容,实际结果应该为5
conexpr的递归:
constexpr int m_pow(int base, int exp)noexcept { return (exp == 0) ? 1 : base * m_pow(base, exp - 1); } ... constexpr int res = m_pow(2, 5);//编译时计算 static_assert(res == 32, "false");
注意:你有没有注意到,函数就一条语句? 只要你在函数中使用constexpr,则你必须保证函数就一行语句: return语句。 否则constexpr的作用就相当于没有,它就是一个普通的函数了,不是编译时常量了。
-
constexpr的声明与实现一定要在使用者的前面!
-
使用constexpr标记的函数你怎么知道就一定执行了constexpr的功能呢? 即编译时就完成了。
- 答案: 查看反汇编,这是调用constexpr求幂的函数,可以发现它直接把一个值赋值给了变量,完成了赋值,我们都知道普通的函数调用过程一定会经历 call 与 ret的过程,因此可以确定,他的确是在编译时就完成了!!
类中constexpr
在类中也可以使用constexpr,可以放在除析构函数以外,任意的成员函数中,静态成员函数,构造函数都可以。
构造函数使用constexpr: constexpr 修饰类的构造函数时:要求该构造函数的函数体必须为空,且采用初始化列表的方式为各个成员赋值时,必须使用常量表达式。
class Foo { public: //注意,constexpr 修饰类的构造函数时: //要求该构造函数的函数体必须为空,且采用初始化列表的方式为各个成员赋值时,必须使用常量表达式。 constexpr Foo(int a, const char* s)noexcept :a(a), name(s) {} } ... constexpr Foo a{ 10, "ylh"}; //编译时初始化
完成一个类的浅拷贝的constexpr函数:
template <typename T> constexpr T m_copy(const T& t)noexcept { return t; } ... //如果缺少 constexpr:call m_copy<Foo> (07FF7B96F13DEh) 说明这就是一个普通的函数 //如果带上 constexpr,则会发现不会调用call,即成功实现了常量表达式函数 constexpr Foo b = m_copy(a); // OK a在上面已经通过constexpr调用了constexpr的构造函数,因此b也通过constexpr实现了编译时拷贝。
接收多个参数的constexpr函数:
constexpr Foo ExChange(const Foo& a, const Foo& b) { return { a.GetA() / 2,b.GetName() }; } ... // 不会调用 call ExChange (07FF6F75013F7h) constexpr Foo ExRes = ExChange(a, b); //ok //使用static_assert判断正确性: static_assert(ExRes.GetA() == 5, "测试"); //是对的,因为ExRes.GetA()在函数中是来自与a的GetA函数除以2得到的,所以是10/2得5,因此正确
本文来自博客园,作者:hugeYlh,转载请注明原文链接:https://www.cnblogs.com/helloylh/p/17209664.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)