【C++杂货铺】内联函数、auto、范围for、nullptr(一)

简介: 【C++杂货铺】内联函数、auto、范围for、nullptr(一)

2feef2da9ae84297912203047651a902.gif

一、内联函数

 普通的函数在调用的时候会开辟函数栈帧,会产生一定量的消耗,在C语言中可以用宏函数来解决这个问题,但是宏存在以下缺陷:复杂、容易出错、可读性差、不能调试。为此,C++中引入了内联函数这种方法。

1.1 定义

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

🪆普通函数:

int Add(int x, int y)//这里的Add是一个普通函数
{
  return x + y ;
}
int main()
{
  int ret = 0;
  ret = Add(3, 5);
  cout << ret << endl;
  return 0;
}

e99e0cc9305c47c3a45bf48bd585cba6.png

🪆内联函数:

inline int Add(int x, int y)
{
  return x + y ;
}
int main()
{
  int ret = 0;
  ret = Add(3, 5);
  cout << ret << endl;
  return 0;
}

aa1c9d3d4b2b465ea86010f2bfcd7e66.png

注意:在默认的Debug模式下,内联函数是不会展开的,需要进行设置,设置过程如下:


662e0dbcd2a74320a06985c666810b12.png


6d54dde74876459fa1e32e5b2b032c91.png

3b5c9c93c51044b48712895a54d31b5f.png


1.2 特性

inline是一种以时间换空间的做法,如果编译器将函数当成内联函数处理,在编译阶段,会用函数体替换函数调用。缺陷:可能会使目标文件变大,优点:少了调用开销,提高程序运行效率。

inline对编译器而言只是建议,不同的编译器关于inline的实现机制可能不同,一般建议:将函数规模小的(即函数不是很长,具体没有准确的说法,取决于编译器内部实现)、不是递归、且频繁调用的函数采用inline修饰,否则编译器会忽略inline特性。

inline建议函数声明和定义不能分离,因为内联函数在预处理阶段就直接展开,因此内联函数不会进符号表,因此如果声明和定义分离,头文件只有声明,在预处理阶段,头文件展开,只知道该函数是一个内联函数,没有对应函数的定义,因此就无法完成替换,那就只能等通过call在链接阶段去找该函数,但是它是内联函数,没有进符号表,所以链接阶段就会报错。

🪆为什么是函数规模小?

 假设一个函数经过编译,得到五十条汇编指令。普通情况下,调用此函数只需要一条call指令,调用10000此也就10000条call指令,但是如果把这个函数设置成内联函数,指令的数量就会大大增加,因为内联函数完成的是替换,把所有调用它的地方,都用函数体去替换,这也就意味着,原来1条call指令就能完成的任务,现在替换后就变成了50条指令,假如还是调用了10000次该函数,那就从10000条call指令,变成了500000条指令,其实这就是代码膨胀。

inline int Add(int x, int y)
{
  cout << "xxxxxxxxxxxx" << endl;
  cout << "xxxxxxxxxxxx" << endl;
  cout << "xxxxxxxxxxxx" << endl;
  cout << "xxxxxxxxxxxx" << endl;
  cout << "xxxxxxxxxxxx" << endl;
  cout << "xxxxxxxxxxxx" << endl;
  cout << "xxxxxxxxxxxx" << endl;
  cout << "xxxxxxxxxxxx" << endl;
  cout << "xxxxxxxxxxxx" << endl;
  cout << "xxxxxxxxxxxx" << endl;
  cout << "xxxxxxxxxxxx" << endl;
  cout << "xxxxxxxxxxxx" << endl;
  return x + y ;
}
int main()
{
  int ret = 0;
  ret = Add(3, 5);
  cout << ret << endl;
  return 0;
}

e1463922a4f0466f9fafe1fb9c4329ea.png


对于上面函数体比较长的函数,即使我们人为规定了它是内联,但最终还是通过call指令去调用函数。

🪆为什么是被频繁调用?

 因为普通函数在调用的时候会创建函数栈帧,若频繁调用就会频繁的创建栈帧,增加消耗。宏和内联,就是为了解决开销问题。如果调用的次数不多,开辟一点栈帧是无所谓的。

二、auto关键字

2.1 简介

 C++11中规定:auto不再是一个存储类型指示符,而是作为一个新的类型指示符来指示编译器,auto声明的变量必须由编译器在编译时期推导而得。简单来说,auto会根据表达式自动推导类型。

int main()
{
  int a = 0;
  auto b = a;//自动推导出b的类型是int
  auto c = 1.11 + 1;//自动推导出c的类型是double
  cout << typeid(b).name() << endl;//typeid可用来查看变量类型
  cout << typeid(c).name() << endl;
  return 0;
}

0c31b89c6d824d7d80c2966be8c8473c.png

🪆注意:

 使用auto定义变量时必须对其进行初始化,在编译阶段编译器需要根据初始化表达式,来推导auto的实际类型。因此,auto并非是一种“类型”的声明,而是一个类型声明的“占位符”,编译器在编译阶段会将auto替换为变量实际的类型。

int main()
{
  auto a;//错误,必须要初始化
  return 0;
}

4e63d326ee2547cca178e8f8da54fb9f.png


目录
相关文章
|
存储 安全 编译器
【C++】C++特性揭秘:引用与内联函数 | auto关键字与for循环 | 指针空值(一)
【C++】C++特性揭秘:引用与内联函数 | auto关键字与for循环 | 指针空值
205 1
|
安全 程序员 编译器
C++ 11新特性之auto和decltype
C++ 11新特性之auto和decltype
167 3
|
存储 编译器 程序员
【C++】C++特性揭秘:引用与内联函数 | auto关键字与for循环 | 指针空值(二)
【C++】C++特性揭秘:引用与内联函数 | auto关键字与for循环 | 指针空值
162 0
|
程序员 C++ 开发者
C++入门教程:掌握函数重载、引用与内联函数的概念
通过上述介绍和实例,我们可以看到,函数重载提供了多态性;引用提高了函数调用的效率和便捷性;内联函数则在保证代码清晰的同时,提高了程序的运行效率。掌握这些概念,对于初学者来说是非常重要的,它们是提升C++编程技能的基石。
127 0
|
10月前
|
编译器 C++ 开发者
【C++篇】深度解析类与对象(下)
在上一篇博客中,我们学习了C++的基础类与对象概念,包括类的定义、对象的使用和构造函数的作用。在这一篇,我们将深入探讨C++类的一些重要特性,如构造函数的高级用法、类型转换、static成员、友元、内部类、匿名对象,以及对象拷贝优化等。这些内容可以帮助你更好地理解和应用面向对象编程的核心理念,提升代码的健壮性、灵活性和可维护性。
|
6月前
|
人工智能 机器人 编译器
c++模板初阶----函数模板与类模板
class 类模板名private://类内成员声明class Apublic:A(T val):a(val){}private:T a;return 0;运行结果:注意:类模板中的成员函数若是放在类外定义时,需要加模板参数列表。return 0;
163 0
|
6月前
|
存储 编译器 程序员
c++的类(附含explicit关键字,友元,内部类)
本文介绍了C++中类的核心概念与用法,涵盖封装、继承、多态三大特性。重点讲解了类的定义(`class`与`struct`)、访问限定符(`private`、`public`、`protected`)、类的作用域及成员函数的声明与定义分离。同时深入探讨了类的大小计算、`this`指针、默认成员函数(构造函数、析构函数、拷贝构造、赋值重载)以及运算符重载等内容。 文章还详细分析了`explicit`关键字的作用、静态成员(变量与函数)、友元(友元函数与友元类)的概念及其使用场景,并简要介绍了内部类的特性。
258 0
|
8月前
|
编译器 C++ 容器
【c++11】c++11新特性(上)(列表初始化、右值引用和移动语义、类的新默认成员函数、lambda表达式)
C++11为C++带来了革命性变化,引入了列表初始化、右值引用、移动语义、类的新默认成员函数和lambda表达式等特性。列表初始化统一了对象初始化方式,initializer_list简化了容器多元素初始化;右值引用和移动语义优化了资源管理,减少拷贝开销;类新增移动构造和移动赋值函数提升性能;lambda表达式提供匿名函数对象,增强代码简洁性和灵活性。这些特性共同推动了现代C++编程的发展,提升了开发效率与程序性能。
301 12
|
9月前
|
设计模式 安全 C++
【C++进阶】特殊类设计 && 单例模式
通过对特殊类设计和单例模式的深入探讨,我们可以更好地设计和实现复杂的C++程序。特殊类设计提高了代码的安全性和可维护性,而单例模式则确保类的唯一实例性和全局访问性。理解并掌握这些高级设计技巧,对于提升C++编程水平至关重要。
179 16
|
10月前
|
编译器 C语言 C++
类和对象的简述(c++篇)
类和对象的简述(c++篇)