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

C++高级篇学习笔记

文章目录


前言

本文记录C++一些面试难点问题剖析。


1. 左右值和右值引用的作用

  • 左值

可以在=左边,表达式结束后依然存在的持久对象,一般有名字,可以取地址。
 提示: 前置自加/自减 可以做左值;

  • 右值

在=右边,不能取地址,没有名字,临时对象。

提示: 后置自加自减 做右值

但是,右值分两种: 

纯右值:字面值,后置自增自减,算术表达式,返回非引用的函数调用

将亡值:与右值引用相关的表达式,。例如将要被移动的对象

右值引用:

语法:  数据类型 && 变量名= 右值  。就是给右值取个名字,但是右值引用本身变成了左值。

作用:1. 实现移动语义    2. 实现完美转发

左值引用:

例如:

        int a=0;

        int &b = a;  这是普通左值引用

        const int & c = 0; 这是常量左值引用,必须要有const,否则报错。

        所以常量左值引用可以接收常量右值,也就是字面值。

         

移动语义:

C++ 11实现移动语义来减少拷贝: 

对右值使用移动语义可以减少拷贝,对左值可以使用std::move将左值转义为右值。

完美转发:

  •  万能引用: T && ,以此为形参,可以接收左值和右值。 

提示: T&&必须这么写,也就是只能用在模板中。如果写成int &&做形参,那只能接收右值。

        对右值引用的两个规则中的第一个也同样影响了旧式的左值引用。回想在pre-11 C++时,对一个引用取引用是是不被允许的,比如A& &会导致一个编译器错误。相比之下,在C++11中,引入了如下所示的引用折叠规则(reference collapsing rules):

        1. A& &变成A&
        2. A& &&变成A&
        3. A&& &变成A&
        4. A&& &&变成A&&

  • 模板函数:std::forward<T>(参数),用于转发参数,如果参数是右值转发完是右值引用,如果是左值,则转发后是左值引用。

 C++11 forward完美转发_Barry__的博客-CSDN博客_c forward

 上述文章解释了完美转发的使用场景和更合理的解释。

2. 智能指针

  • unique_ptr

独占式拥有,保证同一时间只有一个智能指针指向该对象。

#include<iostream>
#include<memory>
using namespace std;
int main(){unique_ptr<int> up_x(new int(10));//unique_ptr<int> up_x2(up_x); //没有左值拷贝构造函数//unique_ptr<int> up_x2=up_x;  //没有左值拷贝构造函数unique_ptr<int> up_x2;//up_x2 = up_x;                //没有左值拷贝赋值运算符,因为已被deleteunique_ptr<int> up_x3(unique_ptr<int>(new int(9)));  //有右值拷贝构造up_x2 = std::move(up_x);//可以借助move将up_x赋值给up_x2.此操作完成后up-x不可用,有右值拷贝复制*up_x2 = 99;////*up_x = 22;return 0;
}

shared_ptr

多个智能指针共享指向一个对象,所指对象在最后一个引用被销毁时释放,

 可以使用make_shared函数通过构造函数传入普通指针,get函数获得普通指针。

  • 默认情况下,初始化智能指针的普通指针必须指向一个动态分配的内存,因为智能指针默认调用delete释放内存。但也可以将智能指针绑定到一个类类型但是必须正确定义它的析构函数。例如shared_ptr<T> p(q,d);d为自定义的析构函数对象。

注意事项:shared_ptr可以指向数组,但是需要自定义删除器

关于数组的使用和指派删除器:

        我们经常看到的例子都是单个对象,那数组是不是也可以像这样shared_ptr<int> sp(new int[10]);使用shread_ptr?

        这样是错误的。我们要使用shared_ptr管理数组的话,必须给其制定一个删除器(函数):

shared_ptr<int> sp(new int[10], [](int *p) {delete[] p; });

         这里的匿名函数即是删除器。
        如果没有提供删除器,这段代码就是未定义的。默认情况下,shared_ptr使用delete销毁它所指的对象。如果这个对象是个动态数组,对其使用delete所产生的问题和释放一个动态数组忘记加[]的后果相同。

  • 构造函数是explict的,所以不存在从内置指针到智能指针的隐式类型转换。因此必须使用直接初始化(显式)。

 share_ptr循环引用导致的内存泄漏:

#include<iostream>
#include<memory>
using namespace std;
namespace demo63  //演示智能指针循环引用的问题
{class P2;class P1{public:std::shared_ptr<P2> P2Ptr; //如果换成weak_ptr的就可以打破僵局P1() {cout << "hello P1" << endl;}~P1() {cout << "bye P1\n";}};class P2 {public:std::shared_ptr<P1> P1Ptr; //如果换成weak_ptr的就可以打破僵局P2() {cout << "hello P2\n";}~P2() {cout << "bye P2\n";}};
}
int main()
{using namespace demo63;//shared_ptr<int> sp();//shared_ptr<int> sp(new int[10], [](int *p) {delete[] p; });{shared_ptr<P1> p1p(new P1());cout << "p count :" << p1p.use_count() << endl;shared_ptr<P2> p2p(new P2());cout << "c count :" << p2p.use_count() << endl;p1p->P2Ptr = p2p;cout << "c count :" << p2p.use_count() << endl;p2p->P1Ptr = p1p;cout << "p count :" << p1p.use_count() << endl;}//退出循环后,p1p和p2p释放,他们只是指针而已,所以会调用一次智能指针的析构函数//当p1p要析构的时候,发现本身还被p2p->P1Ptr指着,所以对p2p()的引用只是减一,p1p就析构了,不存在了//当p2p要析构的时候,发现本身被先前p1p的P2Ptr指针引用这,所以,只是引用减一,然后p2p被销毁。//而此时,对象P2和P1都没有被释放,内部的P1Ptr指针和P2Ptr指针还在相互指向着对方。导致内存泄露return 0;
}

 PS D:\MyCode> cd "d:\MyCode\" ; if ($?) { g++ main.cpp -o main } ; if ($?) { .\main }
hello P1
p count :1
hello P2
c count :1
c count :2
p count :2

 weak_ptr:


 

 

总结

提示:这里对文章进行总结:

例如:以上就是今天要讲的内容,本文仅仅简单介绍了pandas的使用,而pandas提供了大量能使我们快速便捷地处理数据的函数和方法。

http://www.lryc.cn/news/4559.html

相关文章:

  • gentoo基本安装过程
  • 【LeetCode】1234. 替换子串得到平衡字符串
  • [动手写操作系统]-01-开机运行系统
  • 最长回文子序列问题
  • 月薪11k!从财务专员到软件测试工程师,成都校区小哥哥用三个月实现转行换岗
  • Android 逆向工具大整理,碉堡了
  • 二维数组的定义
  • SpringMVC--获取请求参数、域对象共享数据
  • 2月13日,30秒知全网,精选7个热点
  • 【C++设计模式】学习笔记(2):模式分类与模版方法 Template Method
  • 【Swift 60秒】92 - Nil coalescing
  • python pip安装的包的路径
  • 个人收藏学习
  • 【C++】类和对象---需掌握的功能
  • 2.12、进程互斥的软件实现方法
  • Java面试题-数据库
  • select 与 where、group by、order by、limit 子句执行优先级比较
  • 【Docker】用开源umami监控你的站点访问量
  • java环境配置
  • Linux系统服务:Apache安装及配置应用
  • 动态规划(Dynamic Programming)——背包问题
  • JVM学习02:内存结构
  • 6年软件测试经验,从我自己的角度理解自动化测试
  • 三种方式查看linux终端terminal是否可以访问外网ping,curl,wget
  • 【Call for papers】SIGCOMM-2023(CCF-A/计算机网络/2023年2月15日截稿)
  • Chapter5:机器人感知
  • [acwing周赛复盘] 第 90 场周赛20230211 补
  • 数组
  • MicroBlaze系列教程(4):AXI_UARTLITE的使用
  • GO 中的 init 函数