初始C++ - auto关键字与内联函数

目录

目录

auto关键字

内联函数 

概念

补·宏函数

在编译器中的特性

特性 

指针空值nullptr(C++11) 

C++98中的指针空值        

结束语


auto关键字

随着程序越来越复杂,程序中用到的类型也越来越复杂,经常体现在
1. 类型难于拼写
2. 含义不明确导致容易出错
如下代码
#include <iostream>
using std::cout;
using std::endl;

//auto -- 根据a的类型推导b的类型
#include <string>
#include <map>	//目前难以介绍

// C++11小语法
int main()
{
	std::map<std::string, std::string> m{ { "apple", "苹果" }, { "orange",
   "橙子" },{"pear","梨"} };

	//auto是方便类似于下面的地方
	//std::map<std::string, std::string>::iterator it = m.begin();	//我们会发现这样写不使用auto的话会很长,写起来很不方便
	auto it = m.begin();	//但是使用auto之后,上面的简化就变得很简洁了


	//一般情况下的C++中数组的遍历
	int array[] = { 1,2,3,4,5 };
	for (int i = 0; i < sizeof(array)/sizeof(array[0]); i++)
		cout << array[i] << " ";
	cout << endl;

	//范围for遍历 -- 使用auto
	//依次取array中数据赋值给e,自动判断结束,自动迭代
	for (auto e : array)
		cout << e << " ";
	cout << endl;

	return 0;
}
【注意】
        使用auto 定义变量时必须对其进行初始化,在编译阶段编译器需要根据初始化表达式来推导 auto 的实际类型 。因此 auto 并非是一种 类型 的声明,而是一个类型声明时的 占位符 ,编译器在编 译期会将 auto 替换为变量实际的类型
//1. auto不能作为函数的参数
//此处代码编译失败,auto不能作为形参类型,因为编译器无法对a的实际类型进行推导
void TestAuto(auto a)          //  这种写法是错误的
{}

 
//2. auto不能直接用来声明数组
void TestAuto()
{
    int a[] = { 1,2,3 };
    auto b[] = { 4,5,6 };
}
3. 为了避免与C++98中的auto发生混淆,C++11只保留了auto作为类型指示符的用法
4. auto在实际中最常见的优势用法就是跟以后会讲到的C++11提供的新式for循环,还有
lambda表达式等进行配合使用。

5.另一个注意事项如下代码

int main()
{

	//一般情况下的C++中数组的遍历
	int array[] = { 1,2,3,4,5 };

	//范围for遍历 -- 使用auto
	//依次取array中数据赋值给e,自动判断结束,自动迭代
	for (auto e : array)
		cout << e << " ";
	cout << endl;

	//但是这种写法是错误的

	for (auto e : array)	//这里e是array里面元素的拷贝所以这里改变e的值是影响不了array数组的
	{
		e *= 2;
	}

	for (auto e : array)	//e是array里面元素的拷贝
		cout << e << " ";
	cout << endl;

	//加一个引用就可以解决了,这里的e就是里面元素的别名
	for (auto& e : array)	//这里e是array里面元素的拷贝所以这里改变e的值是影响不了array数组的
	{
		e *= 2;
	}

	for (auto e : array)	//e是array里面元素的拷贝
		cout << e << " ";
	cout << endl;

	return 0;
}

 

        还有一点只能用引用而不能用指针(*),不然就会通过auto之后会成为 (int*)明显是不对的

内联函数 

概念

        以inline修饰的函数叫做内联函数,编译时C++编译器会在调用内联函数的地方展开,没有函数调 用建立栈帧的开销,内联函数提升程序运行的效率。

 

        如果在上述函数前增加inline 关键字将其改成内联函数,在编译期间编译器会用函数体替换函数的调用。

补·宏函数

//宏函数
#define Add(x,y)  ((x) + (y))	//宏函数注意事项 1:不需要加类型 2.不需要加分号 3.需要注意括号的使用!4.宏函数本质上是替换

int main()
{
	//宏函数的使用
	cout << Add(1,2) << endl;		

	//3.外部括号不加容易影响优先级  例如:Add(1,2)*3
	//  内部括号不加  例如:Add(a|b, a&b)

	return 0;
}

 宏函数注意事项

1:不需要加类型

2.不需要加分号

3.需要注意括号的使用!

4.宏函数本质上是替换

内联函数的使用

//内联函数(inline)
inline int ADD(int x, int y)
{
	return x + y;
}
int main()
{

	cout << ADD(1, 2) << endl;

	return 0;
}

在编译器中的特性

debug版本中是不会像宏函数一样展开的。

我们可以在反汇编中查看到,ADD函数还是建立了栈帧,我们使用这个关键字的目的就是要让它不建立函数栈帧,那么是否违背了?

显然并不是这样的,这一行是编译器为了方便程序员调试而做出的行为 

原因:因为需要 调试,假如展开就不可以调试了,当然在release版本中就会展开了(优化)

当然我们也可以让它在debug版本中展开,这需要如下在属性中设置

返回值比较小的情况下是直接使用寄存器来传递的哦

在C++中的经验条款

通常情况下在C++中要使用:inline 来替代宏函数(频繁调用的小函数)  const  enum 来替代常变量

当然我们需要注意以下的几个特性

特性 

 

1.递归函数肯定是不适用的,较长的函数也是不会展开的

以下是在属性让其展开的情况下,左边较短,右边较长 

为什么函数长了以后就不展开了呢?

回答:代码膨胀

 

 

在上面的反汇编也可以看出,不展开的话就call指令一下就可以了,但是展开的话就长的多了

        这里就是在说明,inline是建议,而不是强制。并且是以空间换取时间的一种行为。编译期间处理。

3.不要声明与定义分离 

会出现链接错误!!!(语法没问题,但是编译器找不到了) 加了inline不会进入符号表,无论长不长

生成可执行程序过程为成四个步骤:

1.预处理(Preprocessing)
2.编译(Compilation),
3.汇编(Assemble),
4.链接(Linking)。

1、由.c文件到.i文件,这个过程叫预处理。
2、由.i文件到.s文件,这个过程叫编译。
3、由.s文件到.o文件,这个过程叫汇编。
4、由.o文件到可执行文件,这个过程叫链接。


指针空值nullptr(C++11) 

C++98中的指针空值        

        在良好的C/C++ 编程习惯中,声明一个变量时最好给该变量一个合适的初始值,否则可能会出现不可预料的错误,比如未初始化的指针。如果一个指针没有合法的指向,我们基本都是按照如下
方式对其进行初始化:
void TestPtr()
{
int* p1 = NULL;
int* p2 = 0;
// ……
}

NULL实际是一个宏,在传统的C头文件(stddef.h)中,可以看到如下代码:  

#ifndef NULL
#ifdef __cplusplus
#define NULL   0
#else
#define NULL   ((void *)0)
#endif
#endif

        可以看到,NULL 可能被定义为字面常量 0 ,或者被定义为无类型指针 (void*) 的常量 。不论采取何种定义,在使用空值的指针时,都不可避免的会遇到一些麻烦,比如:

void f(int) {
 cout<<"f(int)"<<endl; 
}

void f(int*) {
 cout<<"f(int*)"<<endl;
 }

int main()
{
 f(0);
 f(NULL);
 f((int*)NULL);

 return 0;
 }

        程序本意是想通过f(NULL) 调用指针版本的 f(int*) 函数,但是由于 NULL 被定义成 0 ,因此与程序的初衷相悖。
        在C++98 中,字面常量 0 既可以是一个整形数字,也可以是无类型的指针 (void*) 常量,但是编译器默认情况下将其看成是一个整形常量,如果要将其按照指针方式来使用,必须对其进行强转(void*)0。

 注意:

1.在使用nullptr表示指针空值时,不需要包含头文件,因为nullptr是C++11作为新关键字引入 的

2. 在C++11中,sizeof(nullptr) 与 sizeof((void*)0)所占的字节数相同。

3. 为了提高代码的健壮性,在后续表示指针空值时建议最好使用nullptr。

结束语

最是人间留不住,朱颜辞镜花辞树。
                                                                ——王国维《蝶恋花•阅尽天涯离别苦》

  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

清风玉骨

爱了!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值