面试之快速学习C++11-完美转发,nullptr, shared_ptr,unique_ptr,weak_ptr,shared_from_this
完美转发及其实现
- 函数模版可以将自己的参数完美地转发给内部调用的其他函数。所谓完美,即不仅能准确地转发参数的值,还能保证被转发参数的左右值属性不变
- 引用折叠:如果任一引用为左值引用,则结果为左值引用,否则为右值引用。
& && -> &
&& & -> &
& & -> &
&& && -> &&
void actualRun(int a) {}
template <typename T>
void testPerfectForward(T &¶m) {actualRun(param);
}void testPerfectForwardMain() {int a = 0;testPerfectForward(a);
}
上述 T 为int &。 那么整个为 int & &&-> int &
回到完美转发,假设现在我需要转发a,那么注意一下实现完美转发需要这样写
template <typename T>
void testPerfectForward1(T &¶m) {actualRun(std::forward(param));
}
forward大致实现原理
static_cast + &&
template <typename T>
T&& forwad(T ¶m) {return static_cast<T&&>(param);
}
注意其实std::move底层实现也是 static_cast
C++11 nullptr:初始化空指针
- #define NULL 0
#include <iostream>
using namespace std;void isnull(void *c){cout << "void*c" << endl;
}
void isnull(int n){cout << "int n" << endl;
}
void testNull1() {isnull(0);//isnull(NULL);//Call to 'isnull' is ambiguousisnull((void*)NULL);/*int nvoid*c*/
}
1 . nullptr 是 nullptr_t 类型的右值常量,专用于初始化空类型指针。nullptr_t 是 C++11 新增加的数据类型,可称为“指针空值类型”。也就是说,nullpter 仅是该类型的一个实例对象(已经定义好,可以直接使用),如果需要我们完全定义出多个同 nullptr 完全一样的实例对象。
- nullptr 可以被隐式转换成任意的指针类型。故如下:
void testNull2() {isnull(0);//isnull(NULL);//Call to 'isnull' is ambiguousisnull((void*)NULL);isnull(nullptr);/*int nvoid*cvoid*c*/}
- 借助执行结果不难看出,由于 nullptr 无法隐式转换为整形,而可以隐式匹配指针类型,因此执行结果和我们的预期相符
void testNullMain() {
// int *p = 0;
// int *q = NULL;
// testNull1(0);
// testNull1(NULL);
}
.C++11 shared_ptr智能指针
void deleteInt(int *p) {delete []p;
}
void testSharedPtr () {std::cout << "testSharePtr: " << endl;//初始化空的shareptr,引用计数为0不是1std::shared_ptr<int> p1;std::shared_ptr<int> p2(nullptr);std::shared_ptr<int> p3(new int(10));std::shared_ptr<int> p4 = std::make_shared<int>(10);//调用拷贝构造函数std::shared_ptr<int> p5(p4); //或者 p4 = p3;//调用移动构造函数std::shared_ptr<int> p6(std::move(p4)); //或者p6 = std::move(p4)//智能指针可以拷贝,给多个智能指针用,引用计数+1,但是普通指针,只能拷贝给一个智能指针int *p = new int(1);std::shared_ptr<int> pp1(p);
// std::shared_ptr<int> pp2(p); //错误!!!!// 在初始化 shared_ptr 智能指针时,还可以自定义所指堆内存的释放规则,这样当堆内存的引用计数为 0 时,会优先调用我们自定义的释放规则。在某些场景中,自定义释放规则是很有必要的,比如,对于申请的动态数组来说,share—_ptr指针默认的释放规则是不支持释放数组的,值呢个自定义对于的释放规则,如下://释放规则可以使用 C++11 标准中提供的 default_delete<T> 模板类,我们也可以自定义释放规则:std::shared_ptr<int> p10(new int[10], std::default_delete<int[]>());std::shared_ptr<int> p11(new int[10], deleteInt);std::shared_ptr<int> p12(new int[10], [](int *p){delete []p;});std::shared_ptr<int> ppp1 = std::make_shared<int>(10);std::shared_ptr<int> ppp2(ppp1);std::cout << *ppp2 << endl;cout<< ppp2.use_count()<<endl;ppp1.reset();if (p1) {std::cout << "ppp1 is not null !"<< endl;} else {std::cout << "ppp1 is null !"<< endl;}std::cout << *ppp2 << endl;cout<< ppp2.use_count()<<endl;
}
表 1 shared_ptr<T>模板类常用成员方法成员方法名 功 能operator=() 重载赋值号,使得同一类型的 shared_ptr 智能指针可以相互赋值。operator*() 重载 * 号,获取当前 shared_ptr 智能指针对象指向的数据。operator->() 重载 -> 号,当智能指针指向的数据类型为自定义的结构体时,通过 -> 运算符可以获取其内部的指定成员。swap() 交换 2 个相同类型 shared_ptr 智能指针的内容。reset() 当函数没有实参时,该函数会使当前 shared_ptr 所指堆内存的引用计数减 1,同时将当前对象重置为一个空指针;当为函数传递一个新申请的堆内存时,则调用该函数的 shared_ptr 对象会获得该存储空间的所有权,并且引用计数的初始值为 1。get() 获得 shared_ptr 对象内部包含的普通指针。use_count() 返回同当前 shared_ptr 对象(包括它)指向相同的所有 shared_ptr 对象的数量。unique() 判断当前 shared_ptr 对象指向的堆内存,是否不再有其它 shared_ptr 对象再指向它。operator bool() 判断当前 shared_ptr 对象是否为空智能指针,如果是空指针,返回 false;反之,返回 true。*/
C++11 unique_ptr智能指针
unique_ptr 指针指向的堆内存无法同其它 unique_ptr 共享,也就是说,每个 unique_ptr 指针都独自拥有对其所指堆内存空间的所有权
void testUniqueptr() {std::unique_ptr<int> p1(new int(3));
// std::unique_ptr<int> p1(p2);std::unique_ptr<int> p2(std::move(p1));// 默认情况下,unique_ptr 指针采用 std::default_delete<T> 方法释放堆内存。当然,我们也可以自定义符合实际场景的释放规则。值得一提的是,和 shared_ptr 指针不同,为 unique_ptr 自定义释放规则,只能采用函数对象的方式。例如:struct myDel {void operator()(int *p) {delete p;}};std::unique_ptr<int, myDel> p7(new int);
// std::unique_ptr<int, myDel> p6(new int);std::unique_ptr<int> p10(new int);*p10 = 10;//p10释放当前所指堆的所有权, 但该存储空间不会被销毁,转移给了pint *p = p10.release();std::unique_ptr<int> p11;//中 p 表示一个普通指针,如果 p 为 nullptr,则当前 unique_ptr 也变成空指针;反之,则该函数会释放当前 unique_ptr 指针指向的堆内存(如果有),然后获取 p 所指堆内存的所有权(p 为 nullptr)。p11.reset(p);// int *p2 = p;
}
C++11 weak_ptr智能指针
weak_ptr是为了配合shared_ptr而引入的一种智能指针,它不具有普通指针的行为,没有重载*和->两个操作符,它的最大作用在于协助shared_ptr工作,像旁观者那样观测资源的使用情况。
weak_ptr可以从一个shared_ptr或者另一个weak_ptr对象构造,获得资源的观测权。但weak_ptr没有共享资源,它的构造不会引起指针引用计数的增加。
使用weak_ptr的成员函数use_count()可以观测资源的引用计数,另一个成员函数expired()的功能等价于use_count()==0,但更快,表示被观测的资源 (也就是shared_ptr的管理的资源)已经不复存在。
weak_ptr可以使用一个非常重要的成员函数lock()从被观测的shared_ptr 获得一个可用的shared_ptr对象,从而操作资源。但当expired()==true的时候,lock()函数将返回一个存储空指针的shared_ptr。
shared_from_this
#include<memory>class Test: public std::enable_shared_from_this<Test>
{public: Test();~Test();std::shared_ptr<Test> getSharedFromThis(){return shared_from_this();}
}
在什么情况下要使类A继承enable_share_from_this?
使用场合:当类A被share_ptr管理,且在类A的成员函数里需要把当前类对象作为参数传给其他函数时,就需要传递一个指向自身的share_ptr。
我们就使类A继承enable_share_from_this,然后通过其成员函数share_from_this()返回当指向自身的share_ptr。
以上有2个疑惑:
1.把当前类对象作为参数传给其他函数时,为什么要传递share_ptr呢?直接传递this指针不可以吗?
一个裸指针传递给调用者,谁也不知道调用者会干什么?假如调用者delete了该对象,而share_tr此时还指向该对象。
2.这样传递share_ptr可以吗?share_ptr
这样会造成2个非共享的share_ptr指向一个对象,最后造成2次析构该对象。
————————————————
引用链接:https://blog.csdn.net/zk3326312/article/details/79108690
http://c.biancheng.net/view/3730.html
相关文章:
面试之快速学习C++11-完美转发,nullptr, shared_ptr,unique_ptr,weak_ptr,shared_from_this
完美转发及其实现 函数模版可以将自己的参数完美地转发给内部调用的其他函数。所谓完美,即不仅能准确地转发参数的值,还能保证被转发参数的左右值属性不变引用折叠:如果任一引用为左值引用,则结果为左值引用,否则为右…...
android resoure资源图片颜色值错乱
最近androidstudio开发,添加一些颜色值或者drawable资源文件时,运行app,颜色值或者图片对应不上,暂时找不到原因,望告知。 暂时解决方法:...
leetcode第 357/358 场周赛
2817. 限制条件下元素之间的最小绝对差 可能别人有更好的解法,我这写法是不断往线段树中插入数值,每次先插入nums[i-x],然后搜索(1到i)中的最大值和(i到max)中的最小值去更新ans。 class Solution { public:struct node{int mx,…...
Jmeter 分布式性能测试避坑指南
在做后端服务器性能测试中,我们会经常听到分布式。那你,是否了解分布式呢?今天,我们就来给大家讲讲,在企业实战中,如何使用分布式进行性能测试,实战过程中,又有哪些地方要特别注意&a…...
基于SpringCloud的会议室预约系统Java基于微服务的会议室报修系统【源码+lw】
💕💕作者:计算机源码社 💕💕个人简介:本人七年开发经验,擅长Java、微信小程序、Python、Android、大数据等,大家有这一块的问题可以一起交流! 💕💕…...
idea设置忽略大小写
1.点击file 2.点击settings 3.点击Editor选项 4.点击general选项 5.点击code completion 6.点击左上角match case...
re学习(35)攻防世界-no-strings-attached(动调)
参考文章:re学习笔记(28)攻防世界-re-no-strings-attached_Forgo7ten的博客-CSDN博客 攻防世界逆向入门题之no-strings-attached_攻防世界 no-strings-attached_沐一 林的博客-CSDN博客 本人题解: 扔入Exepeinfo中查壳和其他信息…...
STM32 F103C8T6学习笔记8:0.96寸单色OLED显示屏显示字符
使用STM32F103 C8T6 驱动0.96寸单色OLED显示屏: OLED显示屏的驱动,在设计开发中OLED显示屏十分常见,因此今日学习一下。一篇文章从程序到显示都讲通。 文章提供源码、原理解释、测试工程下载,测试效果图展示。 目录 OLED驱动原理—IIC通信…...
vscode的配置和使用
1.侧边栏调整大小 放大:View -> Appearance -> Zoom in(快捷键Ctrl ) 缩小:View -> Appearance -> Zoom out(快捷键Ctrl -) 侧边栏字体调整到合适大小后,可以按下一步调整代码区…...
SpringBoot统⼀功能处理
前言🍭 ❤️❤️❤️SSM专栏更新中,各位大佬觉得写得不错,支持一下,感谢了!❤️❤️❤️ Spring Spring MVC MyBatis_冷兮雪的博客-CSDN博客 本章是讲Spring Boot 统⼀功能处理模块,也是 AOP 的实战环节&…...
LeetCode 每日一题 2023/8/14-2023/8/20
记录了初步解题思路 以及本地实现代码;并不一定为最优 也希望大家能一起探讨 一起进步 目录 8/14 617. 合并二叉树8/15 833. 字符串中的查找与替换8/16 2682. 找出转圈游戏输家8/17 1444. 切披萨的方案数8/18 1388. 3n 块披萨8/19 2235. 两整数相加8/20 8/14 617. 合…...
进入微服务阶段后的学习方法
微服务SpringCloud学习的特点 陌生,多,复杂。 技术陌生,技术栈多,实现复杂。 学习方式 对于每一个组件: 1.知道是什么、有什么用 2.知道操作步骤(跟着讲义操作即可),包括&#…...
C/C++中const关键字详解
为什么使用const?采用符号常量写出的代码更容易维护;指针常常是边读边移动,而不是边写边移动;许多函数参数是只读不写的。const最常见用途是作为数组的界和switch分情况标号(也可以用枚举符代替),分类如下:…...
【2023新教程】树莓派4B开机启动-树莓派第一次启动-树莓派不使用显示器启动-树莓派从购买到启动一步一步完全版!
背景 闲来无事,在咸鱼上买了一个树莓派4B。买来配件都十分齐全,于是就想着启动来测试一下。下面是树莓派无显示器第一次启动的全过程,包含安装系统。 网上的教程大多需要额外使用显示器、鼠标、键盘之类的外设。然而,树莓派本身就…...
LA@2@1@线性方程组和简单矩阵方程有解判定定理
文章目录 矩阵方程有解判定定理线性方程组有解判定特化:齐次线性方程组有解判定推广:矩阵方程 A X B AXB AXB有解判定证明推论 矩阵方程有解判定定理 线性方程组有解判定 线性方程组 A x b A\bold{x}\bold{b} Axb有解的充分必要条件是它的系数矩阵A和增广矩阵 ( A , b ) (A,…...
如何使用ChatGPT创作一个小说式的虚构的世界
世界构建也许是小说写作中最重要的一环,但也可能非常耗时。让ChatGPT加快这一过程吧。 写小说最棒的一点就是有机会从零开始创造一个新世界。你可以创造超凡脱俗的景观,赋予人物魔法。神话故事可以存在于你小说中的现实世界,而传统可以帮助你…...
用于量子通信和互联网的光量子芯片
近年来,新兴的光量子芯片在量子通信和量子互联网领域取得了重大进展。光量子芯片芯片具有可扩展、稳定和低成本等特点,为微型化应用开辟了新的可能性。 7月14日,一篇发表在《light: science & applications》的文章概述了用于量子通信的光…...
11. Vuepress2.x 关闭夜间模式
修改 docs/.vuepress/config.ts 配置文件 设置 themeConfig.darkMode属性详见 官网 module.exports {host: localhost, // ipport: 8099, //端口号title: 我的技术站, // 设置网站标题description: 描述:我的技术站,base: /, //默认路径head: [// 设置 favor.ico&a…...
netty实现websocket通信
调用注意: 1、端口一定要是可以访问的。 2、依赖必须注意和其他版本冲突,比如redis的springboot starter包,会与5.0版本冲突。 <netty.version>4.1.74.Final</netty.version> <dependency><groupId>io…...
两个list如何根据一个list中的属性去过滤掉另一个list中不包含这部分的属性,用流实现
你可以使用Java 8的流来实现这个功能。假设你有两个包含对象的List,每个对象有一个属性,你想根据一个List中的属性值来过滤掉另一个List中不包含这个属性值的对象。下面是一种使用流的方式来实现这个功能 import java.util.ArrayList; import java.util…...
【力扣数据库知识手册笔记】索引
索引 索引的优缺点 优点1. 通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。2. 可以加快数据的检索速度(创建索引的主要原因)。3. 可以加速表和表之间的连接,实现数据的参考完整性。4. 可以在查询过程中,…...
.Net框架,除了EF还有很多很多......
文章目录 1. 引言2. Dapper2.1 概述与设计原理2.2 核心功能与代码示例基本查询多映射查询存储过程调用 2.3 性能优化原理2.4 适用场景 3. NHibernate3.1 概述与架构设计3.2 映射配置示例Fluent映射XML映射 3.3 查询示例HQL查询Criteria APILINQ提供程序 3.4 高级特性3.5 适用场…...
uni-app学习笔记二十二---使用vite.config.js全局导入常用依赖
在前面的练习中,每个页面需要使用ref,onShow等生命周期钩子函数时都需要像下面这样导入 import {onMounted, ref} from "vue" 如果不想每个页面都导入,需要使用node.js命令npm安装unplugin-auto-import npm install unplugin-au…...
页面渲染流程与性能优化
页面渲染流程与性能优化详解(完整版) 一、现代浏览器渲染流程(详细说明) 1. 构建DOM树 浏览器接收到HTML文档后,会逐步解析并构建DOM(Document Object Model)树。具体过程如下: (…...
P3 QT项目----记事本(3.8)
3.8 记事本项目总结 项目源码 1.main.cpp #include "widget.h" #include <QApplication> int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w;w.show();return a.exec(); } 2.widget.cpp #include "widget.h" #include &q…...
数据链路层的主要功能是什么
数据链路层(OSI模型第2层)的核心功能是在相邻网络节点(如交换机、主机)间提供可靠的数据帧传输服务,主要职责包括: 🔑 核心功能详解: 帧封装与解封装 封装: 将网络层下发…...
04-初识css
一、css样式引入 1.1.内部样式 <div style"width: 100px;"></div>1.2.外部样式 1.2.1.外部样式1 <style>.aa {width: 100px;} </style> <div class"aa"></div>1.2.2.外部样式2 <!-- rel内表面引入的是style样…...
今日学习:Spring线程池|并发修改异常|链路丢失|登录续期|VIP过期策略|数值类缓存
文章目录 优雅版线程池ThreadPoolTaskExecutor和ThreadPoolTaskExecutor的装饰器并发修改异常并发修改异常简介实现机制设计原因及意义 使用线程池造成的链路丢失问题线程池导致的链路丢失问题发生原因 常见解决方法更好的解决方法设计精妙之处 登录续期登录续期常见实现方式特…...
Android第十三次面试总结(四大 组件基础)
Activity生命周期和四大启动模式详解 一、Activity 生命周期 Activity 的生命周期由一系列回调方法组成,用于管理其创建、可见性、焦点和销毁过程。以下是核心方法及其调用时机: onCreate() 调用时机:Activity 首次创建时调用。…...
pycharm 设置环境出错
pycharm 设置环境出错 pycharm 新建项目,设置虚拟环境,出错 pycharm 出错 Cannot open Local Failed to start [powershell.exe, -NoExit, -ExecutionPolicy, Bypass, -File, C:\Program Files\JetBrains\PyCharm 2024.1.3\plugins\terminal\shell-int…...
