当前位置: 首页 > news >正文

【C++进阶篇】C++11新特性(上篇)

💡 解锁C++11新技能:初始化、类型推导与智能指针的奥秘!

  • 一. C++11简介
    • 1.1 C++11发展历史
  • 二. 初始化列表
    • 2.1 内置类型
    • 2.2 initializer_list详解
  • 三. 简化声明
    • 3.1 auto 自动推导类型
      • 3.2.1 注意事项
    • 3.3 decltype 获取推导类型
      • 3.3.1 没有括号
      • 3.3.2 有括号
      • 3.3.3 左值
      • 3.3.4 右值
  • 四. 智能指针
    • 4.1 RAII
    • 4.2 分类
  • 五. 最后

一. C++11简介

1.1 C++11发展历史

C++11的前身是C++0x,其标准化历程跨越近十年:

  • 2003年:C++03发布(小修小补版本),ISO委员会启动C++0x项目,原计划200X年完成。
  • 2005年:提出“Concepts”(概念)特性,但因复杂度被推迟至C++20
  • 2007年:草案初稿完成,因特性过多首次延期。
  • 2010年:特性冻结,提交最终委员会草案(FDIS)。
  • 2011年8月12日:ISO正式批准为ISO/IEC 14882:2011,同年9月标准发布,终结了C++98/03时代。

实践:C++每隔3年更新一次

二. 初始化列表

列表初始化 { } 几乎适用于任意数据类型,成为现代编码的推荐方式。合理利用其特性可以可显著提升可读性和健壮性。

2.1 内置类型

C++内置类型几乎都具有一个默认的构造函数。行为:对值进行拷贝。

#include<iostream>
using namespace std;int main()
{//内置类型的构造函数int a(10);char x('c');cout << a << " " << x << endl;return 0;
}

在这里插入图片描述
C++11扩大了{}的范围,对任意类型数据都可以使用其进行初始化。

#include<iostream>
using namespace std;int main()
{//内置类型的构造函数int a{ 10 };int arr[]{ 1,2,3,4,5 };cout << a << " " << arr[0] << endl;return 0;
}

在这里插入图片描述
本质:使用初始化列表{}构造一个临时对象,再用该临时对象拷贝构造,被编译器优化成直接构造。
如何验证呢???思路:就是使用某种关键字,该关键字具有防止隐式类型转换的功能。

下面写出一个简单Date类

在这里插入图片描述
从结果中可以看出没有什么问题,下面我们将构造函数用 explicit 修饰。

  • explicit 关键字用于修饰构造函数,它的主要作用是:
  1. 防止编译器进行隐式类型转换。
  2. 当构造函数被标记为explicit时,这个构造函数就只能被显式地调用,而不能被编译器用于隐式类型转换。
  • 如下图:

在这里插入图片描述

  • 本质:
  1. 使用复制列表初始化 (Date d1 = { 2023, 11,8 }😉 时,由于这种方式可能涉及隐式转换(创建临时对象),而构造函数是explicit的,所以编译器阻止了这种隐式转换,导致初始化失败。
  2. 直接列表初始化 (Date d2{ 2023, 11,8 }😉 是直接调用构造函数,不涉及隐式转换,因此即使构造函数是explicit的,初始化仍然可以成功。

2.2 initializer_list详解

int main()
{auto arr = { 1,2,3,4,5 };cout << typeid(arr).name() << endl;return 0;
}

在这里插入图片描述

  • 注意:并不是使用{}就是 initializer_list -> 看下图:

在这里插入图片描述
该类具有size(),begin(),end(),用于遍历该类中的数据。同时该类具有迭代器,所以支持范围for遍历。值得注意的是:C++库中vector,list,map都具有initializer_list该类的构造。

  • 更简洁的写法:

int main()
{pair<string,string> kv1(make_pair("sort", "排序"));//传统写法unordered_map<string, string> dict{{ "banana","香蕉" }, { "insert","插入" }, { "orange","橙子" }};dict.insert(kv1);dict.insert({ "right","右边" });//现代写法return 0;
}

可以看出再插入时前面代码较多,后面的代码简洁且易懂。

三. 简化声明

对于一个数据类型可能它的类型非常长,在上篇红黑树封装就使用过,如下:
在这里插入图片描述

3.1 auto 自动推导类型

auto一般适用于对于复杂类型,类型很长,或不关心,就可以考虑使用auto,大大简化代码的复杂化。

int main()
{unordered_map<string, string> dict{ { "banana","香蕉" }};//都是哈希表的初始迭代器,只是用不同的变量存储unordered_map<string, string>::iterator it = dict.begin();auto it1 = dict.begin();cout << typeid(it).name() << endl;cout << typeid(it1).name() << endl;return 0;
}
  • 输出结果:

在这里插入图片描述

3.2.1 注意事项

  1. 类型推导规则:auto类型推导会忽略顶层const和引用语义。
int x = 10;
auto a = x; // a的类型被推导为intconst int& ref = x;
auto b = ref; // b的类型被推导为int(顶层const和引用被忽略)
  1. 必须初始化:使用auto声明的变量必须进行初始化,否则编译器无法推导其类型,会导致编译错误。
auto c; // 错误:未初始化的auto变量
  1. 指针和引用:当使用auto声明指针或引用时,需要显式指定指针或引用符号。
int x = 10;
int* ptr = &x;//auto ptrAuto = ptr;
auto* ptrAuto = ptr; // ptrAuto的类型是int*(指针)
auto& refAuto = x;  // refAuto的类型是int&(引用)
  1. 函数返回值:在C++14及以后的标准中,auto可以用于函数返回类型,此时函数的返回类型由return语句推导得出。
auto add(int a, int b) {return a + b; // 返回类型被推导为int
}

3.3 decltype 获取推导类型

decltype 是一个类型推导关键字,它用于查询表达式的类型。
语法如下:

decltype(expression)
其中 expression 是任意一个合法的 C++ 表达式。decltype 会分析这个表达式,并推导出其类型。

3.3.1 没有括号

如果 expression 是一个没有用括号括起来的标识符(比如变量名、函数名、类名等)或者一个类成员访问表达式(比如 obj.member 或 ptr->member),那么 decltype(expression) 的类型就是该表达式结果的类型。

int x = 0;
decltype(x) y = 10; // y 的类型是 intstruct MyStruct { int a; };
MyStruct s;
decltype(s.a) z = 20; // z 的类型是 int

3.3.2 有括号

如果 expression 是一个用括号括起来的标识符(比如 (x)),那么 decltype(expression) 的类型是该标识符的类型的左值引用(即 T&,其中 T 是标识符的类型)。

int x = 0;
decltype((x)) ref = x; // ref 的类型是 int&
ref = 20; // 修改 ref 也会修改 x

3.3.3 左值

如果 expression 是一个左值(可以出现在赋值语句左边的表达式),那么 decltype(expression) 的类型是该表达式类型的左值引用(即 T&)。

int arr[5] = {0};
decltype(arr[0]) elem_ref = arr[0]; // elem_ref 的类型是 int&int& ref_x = x;
decltype(ref_x) another_ref = x; // another_ref 的类型是 int&

3.3.4 右值

如果 expression 是一个右值(比如字面量、临时对象、函数调用返回的非引用类型等),那么 decltype(expression) 的类型就是该表达式结果的类型。

int func() { return 0; }
decltype(func()) val = 10; // val 的类型是 intdecltype(10) another_val = 20; // another_val 的类型是 int

四. 智能指针

4.1 RAII

RAII是C++中一种重要的资源管理技术,全称为Resource Acquisition Is Initialization,即资源获取即初始化。它是一种利用对象的生命周期来自动管理资源的技术,能够有效地防止资源泄漏,提高代码的健壮性和可维护性。

  • RAII的核心思想是将资源的生命周期与对象的生命周期紧密绑定。具体来说,它遵循以下两个原则:
  1. 资源获取即初始化(Resource Acquisition Is Initialization):在对象的构造函数中完成资源的获取(分配)。这意味着,当对象被创建时,它所管理的资源也被同时获取。
  2. 资源释放即析构(Resource Release Is Destruction):在对象的析构函数中完成资源的释放(清理)。这意味着,当对象生命周期结束,被销毁时,它所管理的资源也会被自动释放。

简单点说:就是利用C++的特性,一个对象被创建自动调用构造函数,该对象生命周期时,自动周期结束自动调用析构函数,清理和释放资源。

4.2 分类

C++11 的智能指针有 u n i q u e p t r \color{Red}unique_ptr uniqueptr a u t o p t r \color{Red}auto_ptr autoptr s h a r e d p t r \color{Red}shared_ptr sharedptr w e a k p t r \color{Red}weak_ptr weakptr是专门用来解决 s h a r e d p t r \color{Red}shared_ptr sharedptr存在循环引用,导致内存泄漏的方案。 u n i q u e p t r \color{Red}unique_ptr uniqueptr a u t o p t r \color{Red}auto_ptr autoptr这两个智能指针区别在于是否支持拷贝。
推荐使用: s h a r e d p t r \color{Red}shared_ptr sharedptr,如果某种场景不需要拷贝,推荐使用 u n i q u e p t r \color{Red}unique_ptr uniqueptr,最不推荐使用: a u t o p t r \color{Red}auto_ptr autoptr
详细细节见下篇文章。
下面来展示一个简单例子来看一下过程,示例代码如下:

#include<memory>
class A
{
public:A(){cout << "A()" << endl;}~A(){cout << "~A()" << endl;}
};
int main()
{shared_ptr<A> a(new A);return 0;
}

输出结果:
在这里插入图片描述
可以看到析构函数被调用了,资源被正确的清理。

五. 最后

本文深入探讨了C++11的关键特性,涵盖其发展历程、列表初始化、类型推导简化及智能指针等核心主题。C++11作为C++语言的重大更新,引入了诸多改进,显著提升了代码的可读性、安全性和开发效率。列表初始化通过统一的{}语法,增强了类型安全和代码一致性。auto和decltype关键字则简化了复杂的类型声明,使代码更加简洁易读。此外,智能指针和RAII技术的引入,有效解决了资源管理难题,防止了内存泄漏,提高了程序的健壮性。总体而言,C++11的这些特性共同推动了C++语言的现代化进程,使其更加适应现代软件开发的需求。

http://www.xdnf.cn/news/768061.html

相关文章:

  • 【笔记】在 Clang 工具链中降级 NumPy 到 2.2.4
  • JavaWeb预习(jsp)
  • 【AI智能体】Spring AI MCP 从使用到操作实战详解
  • 手机隐藏玩法有哪些?
  • 从线性方程组角度理解公式 s=n−r(3E−A)
  • Android Studio 配置之gitignore
  • Day43
  • 九(3).引用作为方法别名返回
  • 抖音商城抓包 分析
  • LangChain输出格式化实践:提升测试工程师LLM开发效率的完整指南
  • 类和对象:实现日期类
  • mybatisplus的总结
  • 消除F/1噪声
  • Spring Boot 3.X 下Redis缓存的尝试(一):初步尝试
  • CSS 3D 变换中z-index失效问题
  • Ubuntu上进行VS Code的配置
  • 简单工厂模式
  • Spring Boot 3.X 下Redis缓存的尝试(二):自动注解实现自动化缓存操作
  • DeepSeek模型性能优化:从推理加速到资源调度的全栈实践
  • spring-boot接入websocket教程以及常见问题解决
  • 优化WP外贸建站提升用户体验
  • React 核心概念与生态系统
  • React 组件异常捕获机制详解
  • React---day6、7
  • Google机器学习实践指南(TensorFlow六大优化器)
  • 2025GDCPC广东省赛游记(附赛时代码)
  • 【Spring】RAG 知识库基础
  • Docker 镜像制作
  • 【Redis】Zset 有序集合
  • .net consul服务注册与发现