• 【C++】指针与引用(学习笔记)


    一、左值与右值

    左值:编译器为其单独分配了一块存储空间,可以取其地址的,可以放在赋值运算符左边

    右值:数据本身。不能取到其自身地址,只能赋值运算右边

    左值最常见的情况如西数和数据成员的名字

    右值是没有标识符、不可以取地址的表达式,一般也称之为"临时对象"

    二、指针

    1、指针的概念

    1)内存单元内容与地址

    内存由很多内存单元组成。这些内存单元用于存放各种类型的数据

    计算机对内存的每个内存单元都进行了编号,这个编号就称为内存地址,地址决定了内存单元在内存中的位置。

    C++的编译器让我们通过名字(指针变量)来访问这些内存位置

    2)指针的定义

    指针本身就是一个变量,其符合变量定义的基本形式,它存储的是值的地址

    对类型TT*是“到T的指针”类型。一个类型为T*的变量能保存一个类型T的对象的地址

    指针变量是一个专门用来记录变量的地址的变量,通过指针变量可以间接的另一个变量的值

    3)间接访问操作

    通过一个指针访问它所指向地址的过程称为间接访问或引用指针

    这个用于执行间接访问的操作符是单目操作符*

    cout << *d << endl;
    
    • 1

    2、指针数组与数组指针

    指针的数组:T* t[]

    数组的指针:T(*t)[]

    []优先级比较高

    3、const与指针

    关于const修饰的部分:

    1. 看左侧最近的部分
    2. 如果左侧没有,则看右侧

    4、二级指针

    *操作符具有从右向左的结合性

    **这个表达式相当于*(*C),从内向外逐层求值

    int a = 123;
    int* b = &a;
    int** C= &b;
    
    cout << a << *b << **c << endl;
    
    • 1
    • 2
    • 3
    • 4
    • 5

    5、NULL指针

    NULL指针:一个特殊的指针变量,表示不指向任何东西

    对于一个指针,如果已经知道将被初始化为什么地址,那么请
    赋给它这个地址值,否则请把它设置为NULL

    在对一个指针进行间接引用前,请先判断这个指针的值为否为NULL

    6、野指针

    野指针:未初始化和非法的指针

    int *a;
    *a = 12;	// 指针未初始化
    
    • 1
    • 2

    杜绝“野”指针,指向〝垃圾〞内存的指针。if等判断对它们不起作用,因为
    没有置NULL

    1. 指针变量没有初始化
    2. 已经释放不用的指针没有置NULL,如delete和free之后的指针
    3. 指针操作超越了变量的作用范围

    三、c++内存布局

    1、存储区域划分

    2、堆heap

    利用堆(heap)空间动态分配资源

    动态内存具有不确定性,C++让程序员完全接管内存的分配释放

    3、动态分配与回收

    程序通常需要牵涉到三个内存管理器的操作:

    1. 分配一个某个大小的内存块
    2. 释放一个之前分配的内存块
    3. 垃圾收集操作,寻找不再使用的内存块并予以释放(这个回收策略需要实现性能、实时性、额外开销等各方面的平衡,很难有统一和高效的做法)

    C++做了1、2;Java做了1、3

    4、RAII

    RAII (Resource Acquisition Is Initialization)

    C++所特有的资源管理方式。有少量其他语言,如D、Ada 和Rust也采纳了 RAll,但主流的编程语言中,C++是唯一一个依赖 RAII来做资源管理的

    RAIl 依托栈和析构函数,来对所有的资源,包括堆内存在内进行管理。对 RAII 的使用,使得 C++不需要类似于 Java 那样的垃圾收集方法,也能有效地对内存进行管理。RAIl 的存在,也是垃圾收集虽然理论上可以在 C++使用,但从来没有真正流行过的主要原因

    RAII有些比较成熟的智能指针代表

    5、不同变量的对比

    1)栈和堆中的变量

    栈(stack)区堆(heap)区
    作用域函数体内,语句块{}作用域整个程序范围内,new,malloc开始,delete,free结束
    编译期间大小确定变量大小范围确定变量大小范围不确定,需要
    运行期确定
    大小范围Windows系统默认栈大小是1M,linux常见默认的栈大小是8M或10M (ulimit-s)所有系统的堆空间上限是接近内存(虚拟内存)的总大小的(一部分被OS占用)
    内存分配方式地址由高到低减少地址由低到高增加
    内容是否可变可变可变

    2)全局静态存储区和常量存储区的变量

    全局静态存储区常量存储区
    存储内容全局变量,静态变量常量
    编译期间大小是否确定确定确定
    内容是否可变可变不可变

    5、内存泄露

    内存泄漏:程序中己动态分配的堆内存由于某种原因程序末释放或无法释放。造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果

    五、智能指针

    1、auto_ptr

    auto_ptr在c++17中移除

    特点:由new expression 获得对象,在auto_ptr对象销毁时,他所管理的对象也会自动被 delete掉

    所有权转移:不小心把它传递给另外的auto_ptr,原来的指针就不再拥有这个对象了。在拷贝或赋值过程中,会直接剥夺指针对原对象对内存的控制权,转交给新对象,然后再将原对象指针置为nullptr

    2、unique_ptr

    特点:专属所有权,所以unique_ptr管理的内存,只能被一个对象持有,不支持复制和赋值

    移动语义:unique_ ptr禁止了拷贝语义,但提供了移动语义,即可以使用std::move()进行控制所有权的转移

    3、shared_ptr

    shared_ptr通过一个引用计数共享一个对象。当引用计数为0时,该对象没有被使用,可以进行析构

    shared_ptr是为了解决auto_ptr在对象所有权上的局限性,在使用引用计数的机制上提供了可以共享所有权的智能指针(但需要额外的开销)

    循环引用:引用计数会带来循环引用的问题

    循环引用会导致堆里的内存无法正常回收,造成内存泄漏

    4、weak_ptr

    weak_ptr 被设计为与shared_ptr共同工作,以一种观察者模式工作

    作用是协助 shared_ptr 工作,可获得资源的观测权,像旁观者那样观测资源的使用情况

    观察者意味着weak_ptr只对shared_ptr进行引用,而不改变其引用计数。当被观察的shared_ptr失效后,相应的weak_ptr也相应失效

    六、引用

    1、引用概述

    引用:一种特殊的指针,不允许修改的指针

    引用的基本使用:可以认为是指定变量的别名,使用时可以认为时变量本身

    int x1 = 1,x2 = 3:
    int& rx = x1;
    rx = 2;
    cout << x1 << endl;		//2
    cout << rx << endl;		//2
    rx = x2;
    cout << ×1 << endl;		//3
    cout << ry << endl;		//3
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    2、引用存在的意义

    有了指针为什么还需要引用?为了支持函数运算符重载

    有了引用为什么还需要指针?为了兼容C语言

    3、补充

    对内置基础类型(如int,double等)而言,在两数中传递时pass by value 更高效

    对面向对象中自定义类型而言,在函数中传递时pass by reference to const更高效

  • 相关阅读:
    通过有序线性结构构造AVL树
    MinIO Server配置NGINX代理官网文档翻译
    31.JavaScript数组进阶,一网打尽数组操作函数slice、filter、map、reduce、some、every、find、splice
    【kkFileView】源码编译打包构建镜像部署
    创元网配资平台的特点是什么?
    10道不得不会的Docker面试题
    【分析笔记】全志 i2c-sunxi.c 控制器驱动分析
    cnn训练自己数据集
    Linux服务器系统
    LaTeX写作之中译英神器
  • 原文地址:https://blog.csdn.net/wmh1024/article/details/133474231