C++超详细啊境界auto与nullptr的使用

目录
  • 一. auto关键字
    • 1. auto介绍
    • 2. 使用规则
    • 3.auto不能推导的场景
  • 二.基于范围的for循环(C++11)
    • 1. 范围for的语法
    • 2.范围for的使用条件
  • 三. 指针空值nullptr(C++11)

一. auto关键字

1. auto介绍

在早期C/C++中auto的含义是:使用auto修饰的变量,是具有自动存储器的局部变量。

但是在C++11开始,赋予了auto全新的含义即:auto不再是一个存储类型指示符,而是作为一个新的类型指示符来指示编译器,auto声明的变量必须由编译器在编译时期推导而得。

int TestAuto()
{
     return 10;
}
int main()
{
     int a = 10;
     auto b = a;
     auto c = 'a';
     auto d = TestAuto();
     //打印类型
     cout << typeid(b).name() << endl;
     cout << typeid(c).name() << endl;
     cout << typeid(d).name() << endl;
     return 0;
}

注意:

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

auto a; 无法通过编译,使用auto定义变量时必须对其进行初始化

2. 使用规则

(1)auto与指针和引用结合起来使用

用auto声明指针类型时,用auto和auto*没有任何区别,但用auto声明引用类型时则必须加&

int main()
{
     int x = 10;
     const int y = 20;
     //推断没有带解引用操作符的整形指针
     auto a = &x;
     auto a2 = &y;
     //推断带解引用操作符的整形指针
     auto* b = &x;
     //auto* b = x;//注意别写成这样,左边推导一定是指针,x是整形,这样是会报错的
     auto* b2 = &y;
     //推断引用类型
     auto& c = x;
     auto& c2 = y;
     //打印类型
     cout << typeid(a).name() << endl;
     cout << typeid(b).name() << endl;
     cout << typeid(c).name() << endl;
     cout << typeid(a2).name() << endl;
     cout << typeid(b2).name() << endl;
     cout << typeid(c2).name() << endl;
     return 0;
}    

这里发现了一个问题,我们用const修饰了y,但是推导出来的引用类型居然没有被const修饰,但是我们在写代码的时候不加const编译器一定会报错,要注意这里的这个问题

(2)在同一行定义多个变量

当在同一行声明多个变量时,这些变量必须是相同的类型,否则编译器将会报错,因为编译器实际只对第一个类型进行推导,然后用推导出来的类型定义其他变量。

void TestAuto()
{
     auto a = 1, b = 2;
     auto c = 3, d = 4.0; // 该行代码会编译失败,因为c和d的初始化表达式类型不同
}

3.auto不能推导的场景

auto不能作为函数的参数和返回值

// 此处代码编译失败,auto不能作为形参类型,因为编译器无法对a的实际类型进行推导
void TestAuto(auto a)
{}
//不然接收和传参不知道怎么传参和接收
auto TestAuto(int a)
{}

auto不能直接用来声明数组

void TestAuto()
{
     int a[] = {1,2,3};
     auto b[] = {4,5,6};
}

为了避免与C++98中的auto发生混淆,C++11只保留了auto作为类型指示符的用法

auto在实际中最常见的优势用法就是跟以后会讲到的C++11提供的新式for循环,还有lambda表达式等进行配合使用。

二.基于范围的for循环(C++11)

1. 范围for的语法

在C++98中如果要遍历一个数组,可以按照以下方式进行:

void TestFor()
{
     int array[] = { 1, 2, 3, 4, 5 };
     for (int i = 0; i < sizeof(array) / sizeof(array[0]); ++i)
     array[i] *= 2;
     for (int* p = array; p < array + sizeof(array)/ sizeof(array[0]); ++p)
     cout << *p << endl;
}

对于一个有范围的集合而言,由程序员来说明循环的范围是多余的,有时候还会容易犯错误。因此C++11中引入了基于范围的for循环。for循环后的括号由冒号“ :”分为两部分:第一部分是范围内用于迭代的变量, 第二部分则表示被迭代的范围。

void TestFor()
{
     //依次自动取array中的数据赋值给e,自动判断结束
     int array[] = { 1, 2, 3, 4, 5 };
     for(auto& e : array)
     e *= 2;
     for(auto e : array)
     cout << e << " ";
}

注意:与普通循环类似,可以用continue来结束本次循环,也可以用break来跳出整个循环。

2.范围for的使用条件

(1)for循环迭代的范围必须是确定的

对于数组而言,就是数组中第一个元素和最后一个元素的范围;对于类而言,应该提供begin和end的方法,begin和end就是for循环迭代的范围。

以下代码就有问题,因为for的范围不确定:

(数组传参,数组会退化成指针,所以这里接受的是指针,就导致了范围是不确定的)

void TestFor(int array[])
{
     for(auto& e : array)
     cout<< e <<endl;
}

(2)迭代的对象要实现++和==的操作

三. 指针空值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 fun(int)
{
     cout<<"fun(int)"<<endl;
}
void fun(int*)
{
     cout<<"fun(int*)"<<endl;
}
int main()
{
     fun(0);
     fun(NULL);
     fun((int*)NULL);
     return 0;
}

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

注意:

  • 在使用nullptr表示指针空值时,不需要包含头文件,因为nullptr是C++11作为新关键字引入的。
  • 在C++11中,sizeof(nullptr) 与 sizeof((void*)0)所占的字节数相同。
  • 为了提高代码的健壮性,在后续表示指针空值时建议最好使用nullptr。

到此这篇关于C++超详细啊境界auto与nullptr的使用的文章就介绍到这了,更多相关C++ auto与nullptr内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C++中nullptr 和 NULL 的区别及用法

    1. 为什么会有nullptr的出现 目的:nullptr的出现主要是为了替代NULL. 那么,为什么要替代NULL呢? 在NULL的定义中存在会有2种方式,有的编译器会将NULL定义成0,有的编译器会将NULL定义成((void*)0). 那么,这两种定义方式会对c++有什么区别呢? 在c++中不允许( void* )隐式的转成其他类型,在某些编译器把NULL定义成((void*)0)的情况下,当你定义变量去赋值NULL时候,NULL就会变定义为0. 另外,这种问题也会对c++的重载特性造成混

  • C++深入探索内联函数inline与auto关键字的使用

    目录 1.内敛函数 1.1问题引入 1.2内联函数的概念 1.3内敛函数的特性 2.auto关键字 2.1 auto简介 2.2 auto的使用细则 2.3 auto不能推导的场景 2.4 auto与新式for循环使用 1.内敛函数 1.1问题引入 我们在使用C语言中我们都学过函数,我们知道函数在调用的过程中需要开辟栈帧.如果我们需要频繁的调用一个函数,假设我们调用10次Add()函数,那我们就需要建立10次栈帧.我们都知道在栈帧中要做很多事情,例如保存寄存器,压参数,压返回值等等,这个过程是很

  • C++中NULL与nullptr的区别对比

    前言 在编写C程序的时候只看到过NULL,而在C++的编程中,我们可以看到NULL和nullptr两种关键字,其实nullptr是C++11版本中新加入的,它的出现是为了解决NULL表示空指针在C++中具有二义性的问题,为了弄明白这个问题,我查找了一些资料,总结如下. 一.C程序中的NULL 在C语言中,NULL通常被定义为:#define NULL ((void *)0) 所以说NULL实际上是一个空指针,如果在C语言中写入以下代码,编译是没有问题的,因为在C语言中把空指针赋给int和char

  • 详析C++中的auto

    目录 1.auto介绍 2.auto使用细则 3.auto不能推导的场景 1.auto介绍 在早期,C/C++中 auto 的含义是:使用auto修饰的变量,auto是具有自动存储器的局部变量.C++11中标准委员会赋予了auto全新的含义即:auto不再是一个存储类型指示符,而作为一个新的类型指示符来指示编译器,auto声明的变量必须由编译器在编译时期推导而得. 可以使用typeid().name 去打印对象的类型. 案例分析: int TestAuto() {     return 2; }

  • C++11 nullptr实现初始化空指针

    实际开发中,避免产生“野指针”最有效的方法,就是在定义指针的同时完成初始化操作,即便该指针的指向尚未明确,也要将其初始化为空指针. 所谓“野指针”,又称“悬挂指针”,指的是没有明确指向的指针.野指针往往指向的是那些不可用的内存区域,这就意味着像操作普通指针那样使用野指针(例如 &p),极可能导致程序发生异常. C++98/03 标准中,将一个指针初始化为空指针的方式有 2 种: int *p = 0; int *p = NULL; //推荐使用 可以看到,我们可以将指针明确指向 0(0x0000

  • C++11新特性之auto的使用

    前言 C++是一种强类型语言,声明变量时必须明确指出其类型.但是,在实践中,优势我们很难推断出某个表达式的值的类型,尤其是随着模板类型的出现,要想弄明白某些复杂表达式的返回类型就变得更加困难.为了解决这个问题,C++11中引入的auto主要有两种用途:自动类型推断和返回值占位.auto在C++98中的标识临时变量的语义,由于使用极少且多余,在C++11中已被删除.前后两个标准的auto,完全是两个概念. 一.自动类型推断 auto自动类型推断,用于从初始化表达式中推断出变量的数据类型.通过aut

  • C++11关于auto关键字的使用示例

    一.概述 auto关键字在c++98中已经出现,在98中定义为具有自动存储器的局部变量, c++11中标准委员会重新定义了auto关键字,表示一个类型占位符,告诉编译器,auto声明变量的类型必须由编译器在编译时期推导 而得. 注意事项: 1.auto关键字类型推断发生在编译期,程序运行时不会造成效率降低 2.auto关键字定义时就需要初始化 3.auto仅仅是一个占位符,它并不是一个真正的类型, 因此sizeof(auto)是错误的 4.auto不能作为函数的参数 5.auto不能定义数组,如

  • C++ auto类型说明符

    编程时常常需要把表达式的值赋给变量,这就要求在声明变量的时候清楚知道表达式的类型.然而要做到这一点并非那么容易,有时候甚至根本做不到.为了解决这个问题,C++11标准引入了auto类型说明符,用它就能让编译器替我们去分析表达式所属的类型. 与原来那些只对应一种特定类型的说明符不同,auto让编译器通过初值来推算变量类型.显然,auto定义的变量必须要有初始值. 使用auto具有以下几点好处: 可靠性:如果表达式的类型发生更改(包括函数返回值发生更改的情况),它也能工作. 性能:确保将不会进行转换

  • C++超详细啊境界auto与nullptr的使用

    目录 一. auto关键字 1. auto介绍 2. 使用规则 3.auto不能推导的场景 二.基于范围的for循环(C++11) 1. 范围for的语法 2.范围for的使用条件 三. 指针空值nullptr(C++11) 一. auto关键字 1. auto介绍 在早期C/C++中auto的含义是:使用auto修饰的变量,是具有自动存储器的局部变量. 但是在C++11开始,赋予了auto全新的含义即:auto不再是一个存储类型指示符,而是作为一个新的类型指示符来指示编译器,auto声明的变量

  • C++超详细分析红黑树

    目录 红黑树 红黑树的概念 红黑树的性质 红黑树结点的定义 红黑树的插入操作 情况一 情况二 情况三 红黑树的验证 用红黑树封装map.set 红黑树的迭代器 封装map 封装set 红黑树 红黑树的概念 红黑树的概念 红黑树,是一种二叉搜索树,但在每个结点上增加一个存储位表示结点的颜色,可以是Red或Black. 通过对任何一条从根到叶子的路径上各个结点着色方式的限制,红黑树确保没有一条路径会比其他路径长出俩倍,因而是接近平衡的. 红黑树和AVL树都是高效的平衡二叉树,增删改查的时间复杂度都是

  • C++ 超详细快速掌握二叉搜索树

    目录 二叉搜索树概念与操作 二叉搜索树的概念 二叉搜索树的操作 查找 插入 删除 二叉搜索树的应用 二叉树的性能分析 二叉搜索树概念与操作 二叉搜索树的概念 二叉搜索树又称二叉排序树,若它的左子树不为空,则左子树上所有节点的值都小于根节点的值:若它的右子树不为空,则右子树上所有节点的值都大于根节点的值,它的左右子树也分别未二叉搜索树.也可以是一颗空树. int a[] = { 5, 3, 4, 1, 7, 8, 2, 6, 0, 9 }; 二叉搜索树的操作 查找 迭代: Node* Find(c

  • C++ 超详细分析多态的原理与实现

    目录 多态的定义及实现 多态的构成条件 虚函数重写 C++11的override和final 抽象类 多态的原理 虚函数表 动态绑定与静态绑定 单继承和多继承关系的虚函数表 单继承中的虚函数表 多继承中的虚函数表 常见问题 多态的定义及实现 多态的概念:通俗来说,就是多种形态,具体点就是去完成某个行为,当不同的对象去完成时会产生出不同的状态. 比如买票这个行为,当普通人买票时,是全价买票:学生买票时,是半价买票:军人买票时是优先买票. 多态的构成条件 多态是在不同继承关系的类对象,去调用同一函数

  • C++超详细讲解模拟实现vector

    目录 1. 模拟实现vector 2. vector常用接口 2.1 reserve 2.2 resize 2.3 push_back 2.4 pop_back() 2.5 insert 2.6 erase 2.7 构造函数的匹配问题 3. 更深层次的深浅拷贝问题 1. 模拟实现vector 我们模拟实现是为了加深对这个容器的理解,不是为了造更好的轮子. 快速搭一个vector的架子 // vector.h #pragma once #include <assert.h> // 模拟实现 --

  • C语言哈希表概念超详细讲解

    目录 1. 哈希概念 2. 哈希冲突 3. 哈希实现 3.1 闭散列(哈希表) 3.1.1 闭散列的细节 3.1.2 优化后的闭散列 3.2 扩散列(哈希桶) 3.2.1 扩散列的细节 4. 哈希表和哈希桶的比较 5. 结尾语 1. 哈希概念 哈希其实在学排序时已经用过了,就是计数排序.计数排序也是用的一种映射关系. 比如对此数组进行 计数排序 :1 1 9 9 9 3 3 8 8 我用的是绝对映射 ,所以开辟的数组空间 它的大小 必须 能映射到 最大的元素. 但是 对于哈希来讲,可以用决定映射

  • Idea配置超详细图文教程(2020.2版本)

    Idea配置(2020.2版本)1.Idea 设置字体2.Idea配置Maven3.不区分大小写4.自动导包功能及相关优化功能5.自动编译6.多行显示7.单词拼写检查8.idea中 类中显示成员变量和方法9.idea中 查看 类的关系图10.idea中 切换背景图片11.idea中 File Type 过滤12.手动加入快捷键设置 1.Idea 设置字体 settings --> Editor --> Font 2.Idea配置Maven Settings --> Build Tools

  • 超详细小程序定位地图模块全系列开发教学

    前言:如果想最大化吸取本文经验,须有小程序开发基础,本文细节比较多(多看注释的提醒内容),请耐心理解,多动手尝试,收获会更加丰富 1.定位系统使用场景及概述 如美团外卖小程序 点定位 点搜索 显而易见,随便一个电商小程序都需要用到定位服务,那么今天我们做一个类似的定位模块 定位模块总览 外部页面 内部页面(下文说的内外部页面就是指这两个) 好了接下来我们开始动手 2.定位外部模块样式 效果 代码 //wxml <view bindtap="getLocation" class=&

  • mysql-canal-rabbitmq 安装部署超详细教程

    原文 1.1. 开启 MySQL 的 binlog 日志 1.修改 my.cnf 或 my.ini(windows), 添加配置项: # binlog 日志存放路径 log-bin=D:\env\mysql-5.7.28-winx64\binlog # 日志中记录每一行数据被修改的形式 binlog-format=ROW # 当前机器的服务 ID, 如果为集群时不能重复 server_id=1 2.重启 mysql 服务后, 查看配置变量是否生效: mysql> show variables l

  • IntelliJ IDEA2021.1 配置大全(超详细教程)

    一.IDEA下载 idea.jdk.tomcat.maven下载地址请参考上一篇博客:https://blog.csdn.net/DwZ735660836/article/details/115485354?spm=1001.2014.3001.5502 软件jihuo:无限重置试用持续 https://www.jb51.net/article/198343.htm 二.IDEA基本配置 FIle -> Settings 1.设置主题 FIle -> Settings... -> App

随机推荐