c++新特性

本文详细介绍了C++11和C++20的新特性,包括右值引用、新增数据结构如std::unordered_set和std::tuple,enum class,chrono库,auto,线程与mutex,lambda函数,模板,async,智能指针以及C++20的协程、模块和std::shared_mutex等,深入解析了这些特性的使用和优势。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

c++11

右值引用

新增数据结构

新增数据结构
std::forward_list:单向链表,只可以前进,在特定场景下使用,相比于std::list节省了内存,提高了性能
std::unordered_set:基于hash表实现的set,内部不会排序,使用方法和set类似
std::unordered_map:基于hash表实现的map,内部不会排序,使用方法和set类似
std::array:数组,在越界访问时抛出异常,建议使用std::array替代普通的数组
std::tuple:元组类型,类似pair,但比pair扩展性好

enum class

chrono库

atomic

底层实现: 在内核中记录threadid 通过比较threadid来对数据进行更改, lock

auto

thread

mutex

其中lock_guard与shared_ptr相同 提供了一种方便的 RAII style 机制
在类结束会调用析构函数来对mutex进行释放
类 unique_lock 是通用互斥包装器,允许延迟锁定、锁定的有时限尝试、递归锁定、所有权转移和与条件变量一同使用.

lambda function bind

std::function的实例可以存储、复制和调用任何可调用对象,存储的可调用对象称为std::function的目标,若std::function不含目标,则称它为空,调用空的std::function的目标会抛出std::bad_function_call异常。
std::bind通常有两大作用:
将可调用对象与参数一起绑定为另一个std::function供调用
将n元可调用对象转成m(m < n)元可调用对象,绑定一部分参数,这里需要使用std::placeholders

列表初始化

继承构造函数

模板

async

通过async可以直接创建异步的任务,返回的结果会保存在future中,不需要像packaged_task和promise那么麻烦,关于线程操作应该优先使用async,看一段使用代码:

#include <functional>
#include <future>
#include <iostream>
#include <thread>

using namespace std;

int func(int in) { return in + 1; }

int main() {
    auto res = std::async(func, 5);
    // res.wait();
    cout << res.get() << endl; // 阻塞直到函数返回
    return 0;
}

使用async异步执行函数是不是方便多啦。
async具体语法如下:
async(std::launch::async | std::launch::deferred, func, args…);
第一个参数是创建策略:
std::launch::async表示任务执行在另一线程
std::launch::deferred表示延迟执行任务,调用get或者wait时才会执行,不会创建线程,惰性执行在当前线程。
如果不明确指定创建策略,以上两个都不是async的默认策略,而是未定义,它是一个基于任务的程序设计,内部有一个调度器(线程池),会根据实际情况决定采用哪种策略。

智能指针

shared_ptr

shared_ptr使用了引用计数,每一个shared_ptr的拷贝都指向相同的内存,每次拷贝都会触发引用计数+1,每次生命周期结束析构的时候引用计数-1,在最后一个shared_ptr析构的时候,内存才会释放。
如果shared_ptr所表征的引用关系中出现一个环,那么环上所述对象的引用次数都肯定不可能减为0那么也就不会被删除。

weak_ptr

对weak_ptr起的作用,很多人有自己不同的理解,我理解的weak_ptr和shared_ptr的最大区别在于weak_ptr在指向一个对象的时候不会增加其引用计数,因此你可以用weak_ptr去指向一个对象并且在weak_ptr仍然指向这个对象的时候析构它,此时你再访问weak_ptr的时候,weak_ptr其实返回的会是一个空的shared_ptr。实际上,通常shared_ptr内部实现的时候维护的就不是一个引用计数,而是两个引用计数,一个表示strong reference,也就是用shared_ptr进行复制的时候进行的计数,一个是weak reference,也就是用weak_ptr进行复制的时候的计数。weak_ptr本身并不会增加strong reference的值,而strong reference降低到0,对象被自动析构。为什么要采取weak_ptr来解决刚才所述的环状引用的问题呢?需要注意的是环状引用的本质矛盾是不能通过任何程序设计语言的方式来打破的,为了解决环状引用,第一步首先得打破环,也就是得告诉C++,这个环上哪一个引用是最弱的,是可以被打破的,因此在一个环上只要把原来的某一个shared_ptr改成weak_ptr,实质上这个环就可以被打破了,原有的环状引用带来的无法析构的问题也就随之得到了解决

unique_ptr

std::unique_ptr是一个独占型的智能指针,它不允许其它智能指针共享其内部指针,也不允许unique_ptr的拷贝和赋值。使用方法和shared_ptr类似,区别是不可以拷贝

拷贝构造函数和拷贝赋值声明为private

nullptr

因为NULL本质上是个int型的0,其实不是个指针

final & override

final最后一个类
override函数重写了

constexpr char *const ptr; // 指针本身是常量

const char* ptr; // 指针指向的变量为常量
修饰类成员函数,表示在该函数内不可以修改该类的成员变量。
修饰类对象,类对象只能调用该对象的const成员函数
const只表示read only的语义,只保证了运行时不可以被修改,但它修饰的仍然有可能是个动态变量,而constexpr修饰的才是真正的常量,它会在编译期间就会被计算出来,整个运行过程中都不可以被改变,constexpr可以用于修饰函数,这个函数的返回值会尽可能在编译期间被计算出来当作一个常量,但是如果编译期间此函数不能被计算出来,那它就会当作一个普通函数被处理。

c++20

协程

一个线程 无线程切换开销 不用锁机制
线程切换的过程:
线程在进行切换的时候,需要将CPU中的寄存器的信息存储起来,然后读入另外一个线程的数据,这个会花费一些时间
CPU的高速缓存中的数据,也可能失效,需要重新加载
线程的切换会涉及到用户模式到内核模式的切换,据说每次模式切换都需要执行上千条指令,很耗时。
协程的切换之所以快,可能的原因是:
在切换的时候,寄存器需要保存和加载的数据量比较小。
高速缓存可以有效利用
没有用户模式到内核模式的切换操作。
更有效率的调度,因为协程是非抢占式的,前一个协程执行完毕或者堵塞,才会让出CPU,而线程则一般使用了时间片的算法,会进行很多没有必要的切换。

最大的优势就是协程极高的执行效率。因为子程序切换不是线程切换,而是由程序自身控制,因此,没有线程切换的开销,和多线程比,线程数量越多,协程的性能优势就越明显。

第二大优势就是不需要多线程的锁机制,因为只有一个线程,也不存在同时写变量冲突,在协程中控制共享资源不加锁,只需要判断状态就好了,所以执行效率比多线程高很多。

modules

优点
没有头文件
声明实现仍然可分离, 但非必要
可以显式指定那些导出(类, 函数等)
不需要头文件重复引入宏 (include guards)
模块之间名称可以相同不会冲突
模块只处理一次, 编译更快 (头文件每次引入都需要处理)
预处理宏只在模块内有效
模块引入顺序无关紧要

ranges

sort 适用于所有有begin 和 end

std::shared_mutex

shared_mutex的适用场景比较特殊:一个或多个读线程同时读取共享资源,且只有一个写线程来修改这个资源,这种情况下才能从shared_mutex获取性能优势。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值