前言:本文章主要用于个人复习,追求简洁,感谢大家的参考、交流和搬运,后续可能会继续修改和完善。
因为是个人复习,会有部分压缩和省略。
一、内联函数
C语言为了减少小函数的栈帧开销,提供了宏函数,会在预处理阶段展开。
既然C语言已经解决了这种问题,为什么C++还要提供inline函数呢?(宏函数的缺点)
1.宏函数不支持调试(内联在debug模式下默认不可调试,需要设置一下)
2.宏函数语法复杂,容易出错(例如用宏实现一个加法)
3.宏函数没有类型安全的检查
因此,C++推荐把频繁调用的小函数,定义成inline,其会在调用的地方展开,没有栈帧开销
能不能所有函数都搞成内联?
例如这里有一个sort函数有100行指令 ,有10个地方调用,总计是多少指令?
有110条。
如果搞成内联函数,有多少条?
100*10,有1000条指令。
指令变多意味着编译出来的可执行程序变大,内存消耗变多,会使人们的体验变差
内联函数的特性:
1. inline是一种以空间换时间的做法,省去了调用函数的额外开销。(代码很长或有循环或递归的函数不适宜作为内联函数)
2. inline对编译器只是一个建议,编译器会自动优化,如果函数不符合要求,编译器不会将其设为内联。
3. inline不建议声明和定义分离,分离会导致链接错误。因为inline被展开,就没有函数地址了,链接就会找不到。
会发生链接错误的根本原因:内联函数没有地址
直接在类里面定义实现的成员函数,默认就是内联函数
class A
{
public:
void func()
{
cout << "A" << endl;
}
private:
int a;
};
二、auto
auto可以根据变量的类型自动确定自己所定义变量的类型
#include <map>
#include <string>
#include <iostream>
using namespace std;
int main()
{
int a = 10;
//int b = a;
auto b = a;//类型声明成auto,可以根据a的类型自动推导b的类型
map<string, string> m;
//map<string, string>::iterator it = m.begin();
//这里可以根据m.begin()自动推导it的类型是map<string, string>::iterator
auto it = m.begin();
return 0;
}
auto有几个地方不能使用:
1.auto不能作为函数的参数
auto不能作为形参类型,因为编译器无法对a的实际类型进行推导
void test(auto a) {}
2.auto不能直接用来声明数组
void test() { int a[] = {1,2,3}; auto b[] = {4,5,6}; //那么可以这样吗?在创建数组时,auto b[0] = a[1]; auto a = 4.1,b = 4;//也不可以 }
3.auto不能用于强制类型转换
三、范围for
auto真正的意义在于支持C++11的新语法范围for,新语法遍历,更简单,是数组都可以,容器也可以。范围for可以自动遍历,依次取出元素赋值给e,直到结束(e的名字可以改变)
如果想通过范围for改变数据,需要加上&
范围for的使用条件
1. for循环迭代的范围必须是确定的
对于数组而言,就是数组中第一个元素和最后一个元素的范围;对于类而言,应该提供begin和end的方法,begin和end就是for循环迭代的范围。注意:以下代码就有问题,因为for的范围不确定,int array[]表示的不是一个数组,它是一个指针,所以不行2. 迭代的对象要能实现++和==的操作。(关于迭代器这个问题,以后会写)
四、nullptr和NULL
在C++中我们使用nullptr,因为C++中NULL其实是被定义成0的
程序本意是想通过f(NULL)调用指针版本的f(int*)函数,但是由于NULL被定义成0,因此与程序的初衷相悖。
在C++98中,字面常量0既可以是一个整形数字,也可以是无类型的指针(void*)常量,但是编译器默认情况下是将其看成是一个整形常量,如果要将其按照指针方式来使用,必须对其进行强转(void *)。