内联函数
以inline修饰的函数叫做内联函数,编译时C++编译器会在调用内联函数的地方展开,没有函数调用建立栈帧的开销,内联函数提高程序运行的效率。
内联函数优点:可以减少建立销毁栈帧时间的消耗。
我们来对比一下C语言,C语言的解决办法是什么呢?
C语言对此的处理是,写一个宏函数,宏函数在预处理的时候会在调用处展开。(举例包括一些需要注意的点)
#define ADD(x,y) ((x)+(y))
int main()
{
//不能加分号
if (ADD(1, 2))
{}
//外层括号
ADD(1, 2) * 3;//外层括号对于优先级的影响
//里面括号
int a = 1, b = 2;
ADD(a | b, a & b); //如果不加里面的括号,加号的优先级高,会先进行加法运算
return 0;
}
宏函数有一些缺点:
1.不能调试
2.没有类型安全检查
3.容易写错
由于宏非常容易出错,C++设计了内联函数来替代宏
C++的解决办法是利用inline关键字,对于需要频繁调用的小函数,优化后没有栈帧消耗。(举例)
inline int Add(int x, int y)
{
return x + y;
}
int main()
{
int ret = Add(1, 1);
cout << ret << endl;
return 0;
}
在这段代码的汇编代码中,内联函数Add没有被展开!!!
在debug模式下,编译器默认是不会对内联函数进行展开的
对编译器一些功能修改之后,可以在debug下对内联函数进行展开
是不是所有的函数都会形成内联函数呢?内联函数有没有什么缺陷呢?
- inline是一种以空间换时间的做法,如果编译器将函数当成内联函数处理,在编译阶段,会用函数体替换函数调用,缺陷:可能会使目标文件变大,优势:少了调用开销,提高程序运行效率。
- inline对于编译器而言只是一个建议,不同编译器关于inline实现机制可能不同,一般建议:将函数规模较小(即函数不是很长,具体没有准确的说法,取决于编译器内部实现)、不是递归、且频繁调用的函数采用inline修饰,否则编译器会忽略inline特性。
inline int func(int x, int y)
{
int a = 1;
a = 1;
a = 1;
a = 1;
a = 1;
a = 1;
a = 1;
a = 1;
a = 1;
a = 1;
a = 1;
a = 1;
a = 1;
a = 1;
a = 1;
a = 1;
a = 1;
a = 1;
a = 1;
a = 1;
return x + y;
}
int main()
{
ret = func(1, 1);
return 0;
}
解释(样例)
内联不支持声明和定义分离
why???
如果声明和定义分离,会报链接错误!!!
报的错误
原理
只要加了inline属性,都不会进入符号表
建议: 内联函数不要声明和定义分离,直接在.h文件中定义就行
宏的优缺点?
优点:
1.增强代码的复用性。
2.提高性能。
缺点:
1.不方便调试宏。(因为预编译阶段进行了替换)
2.导致代码可读性差,可维护性差,容易误用。
3.没有类型安全的检查 。
C++有哪些技术替代宏?
1.常量定义 换用const enum
2.短小函数定义 换用内联函数
一些小语法
typeid
拿到一个变量类型的字符串
int main()
{
int x = 10;
auto a = &x;
auto* b = &x;
auto& c = x;
//自动推导类型
cout << typeid(a).name() << endl;
cout << typeid(b).name() << endl;
cout << typeid(c).name() << endl;
return 0;
}
auto
推导类型
注意:
一行不能推导不同的类型
auto不能做参数,开辟栈帧,没办法确定需要开辟栈帧的大小
范围for读值和写值
int main()
{
int array[] = { 1,2,3,4,5 };
for (auto& e : array)
{
e *= 2; //修改值
}
//此处也可以用int
/*for (auto e : array)
{
cout << e << endl;
}*/
for (int e : array)
{
cout << e << endl;
}
}
C++中的空指针bug
语言有一个概念叫做向前兼容
nullptr 以关键字的形式来补坑(C++11修正)