C++11中的auto、基于范围的for循环、指针空值nullptr

news2024/9/28 7:19:21

目录

auto关键字

使用原因

历史背景

C++11中的auto 

auto的使用案例

auto + 指针/引用 

同一行定义多个变量

typeid关键字 

基于范围的for循环

范围for的语法

范围for的使用条件

指针空值nullptr

C++98中的指针空值

C++11中的指针空值


auto关键字

使用原因

随着程序越来越复杂,程序中用到的类型也越来越复杂,经常体现在:

  • 类型难于拼写
#include <string>
#include <map>
int main()
{
 std::map<std::string, std::string> m{ { "apple", "苹果" }, { "orange", 
"橙子" }, 
   {"pear","梨"} };
 std::map<std::string, std::string>::iterator it = m.begin();
 while (it != m.end())
 {
 //....
 }
 return 0;
}

//std::map<std::string, std::string>::iterator是一个类型
  • 含义不明确导致容易出错

 我们可以用typedef给类型取别名

#include <string>
#include <map>
typedef std::map<std::string, std::string> Map;
int main()
{
 Map m{ { "apple", "苹果" },{ "orange", "橙子" }, {"pear","梨"} };
 Map::iterator it = m.begin();
 while (it != m.end())
 {
 //....
 }
 return 0;
}

 使用typedef给类型取别名确实可以简化代码,但是typedef有会遇到新的难题:

#include <stdio.h>

typedef char* pstring;
int main()
{
     const pstring p1;    // 编译失败,const char* p1,指针需要初始化
     const pstring* p2;   // 编译成功,因为p2的类型是const* char*
     char** p3 = NULL;    //初始化的二级指针p3
     return 0;
}

为什么p2的类型不是char** 而是const* char*:
const在*左侧:可以改变指向(改换门庭)

const在*右侧:可以改变原来指向的内容(内部改革)

char* const 表示可以更改字符指针所指向的字符中的内容,但是不可以指向其它字符

历史背景

        早期C++中,auto 关键字用于指示变量是自动存储器的局部变量,即显式指定变量类型:

int main() {
    auto int x = 5; // 显示将 x 声明为 int 类型
    return 0;
}

很明显,这种用法与直接声明变量没有太大区别,并不能实现编译时类型推导

C++11中的auto 

基本概念:C++11中,auto不再是一个存储类型指示符,而是一个类型指示符,它会指示编译器在编译阶段推导出被auto修饰的变量的类型

注意事项:

1、auto修饰的变量必须进行初始化(编译器会根据初始化表达式来推导auto的实际类型)

#include <stdio.h>

int TestAuto()
{
    return 10;
}

int main()
{
    int a = 10;

    auto b = a;

    auto c = 'a';

    auto d = TestAuto();

    auto e;//wrong,未进行初始化

    cout << typeid(b).name() << endl;
    cout << typeid(c).name() << endl;
    cout << typeid(d).name() << endl;

    return 0;
}

2、auto不能作为函数的参数(编译器无法对该参数的实际类型进行推导)

void TestAuto(auto a)
{}

3、auto不能直接用来声明数组(没有为什么就是规定)

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

 4、最新的C++标准允许auto做函数的返回值(但是不太推荐?)

auto TestAuto(int a)
{
    return a;
}

 但是如果有多个相关联的函数都使用auto做返回值呢?

int f2()
{
    int ret = 1;
    return ret;
}

auto f1()
{
    auto x = f2();
    return x;
}

auto TestAuto()
{
    auto a = f1();
    return a;
}

int main()
{
    auto it = TestAuto();
    return 0
}

        想要知道it的类型就要去TestAuto看a的类型,a的类型又要去f1函数看x的类型,x的类型又要去f2函数看ret的类型,很明显这很麻烦

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

6、auto在实际中最常见的优势用法就是C++11提供的新式for循环,还有lambda表达式等

auto的使用案例

auto + 指针/引用 

  • auto修饰指针类型时,auto和auto*没有任何区别(auto*能让人一眼看出来就是指针类型)

int x = 10;
auto ptr1 = &x; // ptr1 被推断为 int* 类型
auto* ptr2 = &x; // ptr2 也被推断为 int* 类型

std::cout << *ptr1 << std::endl; // 输出 x 的值:10
std::cout << *ptr2 << std::endl; // 输出 x 的值:10

// 修改原始变量的值
x = 20;

std::cout << *ptr1 << std::endl; // 输出修改后的 x 值:20
std::cout << *ptr2 << std::endl; // 同样输出修改后的 x 值:20
  • auto修饰引用时,必须加&(不加&,c的类型就是整型,而非x的别名)
int x = 10;
auto c = x; // c 被推断为 int 类型
auto& ref = x; // ref 被推断为 int&(x 的引用)类型

x = 20;

std::cout << x << std::endl; // 输出 20
std::cout << c << std::endl; // 输出 10
std::cout << ref << std::endl; // 输出 20

c = 30;

std::cout << x << std::endl; // 输出仍然是 20,因为 c 是一个独立的变量而非对原始变量的引用。

同一行定义多个变量

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

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

typeid关键字 

格式: typeid(变量名).name()

功能:显示变量类型

#include <iostream>
using namespace std;
typedef char* pstring;

int main()
{
    const pstring* p2;
    cout <<typeid(p2).name() << endl;
    return 0;
}

基于范围的for循环

范围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(迭代变量:被迭代的范围)

  • 迭代变量:每次循环中被赋予容器或数组中当前元素值的那个变量
  • 被迭代的范围: 数组就是数组名、类就是begin和end
void TestFor()
{
    int array[] = { 1, 2, 3, 4, 5 };

    for(auto& e : array)//如果想要实现将数组中元素的值翻倍,就得加上引用&,否则e只是一个拷贝
         e *= 2;
    
    for(auto e : array)
         cout << e << " ";
    return 0;
}

#include <iostream>
using namespace std;

int main()
{
        int array[] = { 1, 2, 3, 4, 5 };

        for (auto e : array)//如果想要实现将数组中元素的值翻倍,就得加上引用&,否则e只是一个拷贝
            e *= 2;

        for (auto e : array)
            cout << e << " ";
        return 0;   
}

范围for的使用条件

1、for循环迭代的范围必须确定

  • 数组的范围:数组首元素和最后一个元素之间的范围(个数)
  • 类的范围:begin和end就是for循环迭代的范围
void TestFor(int array[])
{
    for(auto& e : array)//wrong,for的范围不确定
        cout<< e <<endl;
}

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

指针空值nullptr

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在C++中会被定义为字面常量0而在C语言中会被定义成无类型指针(void*)的常量,所以在C++中使用NULL初始化指针时会遇到一些问题:

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)调用指针版本的,但是由于在C++环境下NULL会被定义成0,因此与程序的初衷相悖。

C++11中的指针空值

基本概念:为了解决NULL在C++中会被翻译成0,C++11引入了新的关键字nullptr

作用:用于表示空指针

注意事项:

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

~over~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1486048.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Decoupled Knowledge Distillation解耦知识蒸馏

Decoupled Knowledge Distillation解耦知识蒸馏 现有的蒸馏方法主要是基于从中间层提取深层特征&#xff0c;而忽略了Logit蒸馏的重要性。为了给logit蒸馏研究提供一个新的视角&#xff0c;我们将经典的KD损失重新表述为两部分&#xff0c;即目标类知识蒸馏&#xff08;TCKD&a…

JavaSec 基础之五大不安全组件

文章目录 不安全组件(框架)-Shiro&FastJson&Jackson&XStream&Log4jLog4jShiroJacksonFastJsonXStream 不安全组件(框架)-Shiro&FastJson&Jackson&XStream&Log4j Log4j Apache的一个开源项目&#xff0c;是一个基于Java的日志记录框架。 历史…

python学习笔记------元组

元组的定义 定义元组使用小括号&#xff0c;且使用逗号隔开各个数据&#xff0c;数据是不同的数据类型 定义元组字面量&#xff1a;(元素,元素,元素,......,元素) 例如&#xff1a;(1,"hello") 定义元组变量&#xff1a;变量名称(元素,元素,元素,......,元素)…

哈希表是什么?

一、哈希表是什么&#xff1f; 哈希表&#xff0c;也称为散列表&#xff0c;是一种根据关键码值&#xff08;Key value&#xff09;直接进行访问的数据结构。它通过把关键码值映射到表中一个位置来访问记录&#xff0c;从而加快查找速度。这个映射函数叫做散列函数&#xff08…

C#与VisionPro联合开发——单例模式

单例模式 单例模式是一种设计模式&#xff0c;用于确保类只有一个实例&#xff0c;并提供一个全局访问点来访问该实例。单例模式通常用于需要全局访问一个共享资源或状态的情况&#xff0c;以避免多个实例引入不必要的复杂性或资源浪费。 Form1 的代码展示 using System; usi…

初阶数据结构之---栈和队列(C语言)

引言 在顺序表和链表那篇博客中提到过&#xff0c;栈和队列也属于线性表 线性表&#xff1a; 线性表&#xff08;linear list&#xff09;是n个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使用的数据结构。线性表在逻辑上是线性结构&#xff0c;也就是说是连…

c++之拷贝构造和赋值

如果一个构造函数中的第一个参数是类本身的引用&#xff0c;或者是其他的参数都有默认值&#xff0c;则该构造函数为拷贝构造函数。 那么什么是拷贝构造呢&#xff1f;利用同类对象构造一个新对象。 1&#xff0c;函数名和类必须同名。 2&#xff0c;没有返回值。 3&#x…

差分题练习(区间更新)

一、差分的特点和原理 对于一个数组a[]&#xff0c;差分数组diff[]的定义是: 对差分数组做前缀和可以还原为原数组: 利用差分数组可以实现快速的区间修改&#xff0c;下面是将区间[l, r]都加上x的方法: diff[l] x; diff[r 1] - x;在修改完成后&#xff0c;需要做前缀和恢复…

4.关联式容器

关联式container STL中一些常见的容器&#xff1a; 序列式容器&#xff08;Sequence Containers&#xff09;&#xff1a; vector&#xff08;动态数组&#xff09;&#xff1a; 动态数组&#xff0c;支持随机访问和在尾部快速插入/删除。list&#xff08;链表&#xff09;&am…

奇舞周刊第521期:“一切非 Rust 项目均为非法”

奇舞推荐 ■ ■ ■ 拜登&#xff1a;“一切非 Rust 项目均为非法” 科技巨头要为Coding安全负责。这并不是拜登政府对内存安全语言的首次提倡。“程序员编写代码并非没有后果&#xff0c;他们的⼯作⽅式于国家利益而言至关重要。”白宫国家网络总监办公室&#xff08;ONCD&…

Python3零基础教程之数学运算专题进阶

大家好,我是千与编程,今天已经进入我们Python3的零基础教程的第十节之数学运算专题进阶。上一次的数学运算中我们介绍了简单的基础四则运算,加减乘除运算。当涉及到数学运算的 Python 3 刷题使用时,进阶课程包含了许多重要的概念和技巧。下面是一个简单的教程,涵盖了一些常…

NOC2023软件创意编程(学而思赛道)python初中组决赛真题

目录 下载原文档打印做题: 软件创意编程 一、参赛范围 1.参赛组别:小学低年级组(1-3 年级)、小学高年级组(4-6 年级)、初中组。 2.参赛人数:1 人。 3.指导教师:1 人(可空缺)。 4.每人限参加 1 个赛项。 组别确定:以地方教育行政主管部门(教委、教育厅、教育局) 认…

嵌入式驱动学习第一周——linux的休眠与唤醒

前言 本文介绍进程的休眠与唤醒。 嵌入式驱动学习专栏将详细记录博主学习驱动的详细过程&#xff0c;未来预计四个月将高强度更新本专栏&#xff0c;喜欢的可以关注本博主并订阅本专栏&#xff0c;一起讨论一起学习。现在关注就是老粉啦&#xff01; 行文目录 前言1. 阻塞和非阻…

Doris实战——美联物业数仓

目录 一、背景 1.1 企业背景 1.2 面临的问题 二、早期架构 三、新数仓架构 3.1 技术选型 3.2 运行架构 3.2.1 数据模型 纵向分域 横向分层 数据同步策略 3.2.2 数据同步策略 增量策略 全量策略 四、应用实践 4.1 业务模型 4.2 具体应用 五、实践经验 5.1 数据…

【Java EE】线程安全的集合类

目录 &#x1f334;多线程环境使用 ArrayList&#x1f38d;多线程环境使⽤队列&#x1f340;多线程环境使⽤哈希表&#x1f338; Hashtable&#x1f338;ConcurrentHashMap ⭕相关面试题&#x1f525;其他常⻅问题 原来的集合类, 大部分都不是线程安全的. Vector, Stack, HashT…

EndNote 21:文献整理与引用,一键轻松搞定 mac/win版

EndNote 21是一款功能强大的文献管理软件&#xff0c;专为学术研究者、学生和教师设计。它提供了全面的文献管理解决方案&#xff0c;帮助用户轻松整理、引用和分享学术文献。 EndNote 21软件获取 EndNote 21拥有直观的用户界面和强大的文献检索功能&#xff0c;用户可以轻松地…

昇腾ACL应用开发之硬件编解码dvpp

1.前言 在我们进行实际的应用开发时&#xff0c;都会随着对一款产品或者AI芯片的了解加深&#xff0c;大家都会想到有什么可以加速预处理啊或者后处理的手段&#xff1f;常见的不同厂家对于应用开发的时候&#xff0c;都会提供一个硬件解码和硬件编码的能力&#xff0c;这也是抛…

【C++干货基地】揭秘C++11常用特性:内联函数 | 范围for | auto自动识别 | nullptr指针空值

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏: 《C干货基地》《粉丝福利》 ⛺️生活的理想&#xff0c;就是为了理想的生活! 引入 哈喽各位铁汁们好啊&#xff0c;我是博主鸽芷咕《C干货基地》是由我的襄阳家乡零食基地有感而发&#xff0c;不知道各位的…

基于springboot实现校园爱心捐赠互助管理系统项目【项目源码+论文说明】计算机毕业设计

基于springboot实现校园爱心捐赠互助管理系统演示 摘要 随着互联网及电子商务平台的飞速发展&#xff0c;利用在线平台实现的二手商品交易以及在线捐赠已经非常普遍&#xff0c;很多高校目前还存在贫困生需要通过爱心人士的捐助来完成学业&#xff0c;同时很多高校的大学生也希…

【C++】STL学习之旅——初识STL,认识string类

string类 1 STL 简介2 STL怎么学习3 STL缺陷4 string4.1 初识 string4.2 初步使用构造函数成员函数 5 小试牛刀Thanks♪(&#xff65;ω&#xff65;)&#xff89;谢谢阅读&#xff01;&#xff01;&#xff01;下一篇文章见&#xff01;&#xff01;&#xff01; 1 STL 简介 …