1.指针和自由存储空间 ⭐指针策略是C++内存管理变成理念的核心 ⭐指针与C++基本原理 面向对象编程与传统的过程性编程的区别在于,OOP强调的是在运行阶段(而不是编译阶段)进行决策。例如传统C++声明数组需要指定数组长度,如果要分配200个元素的空间,如果编译阶段进行决策那么就确定是需要200个元素的空间,如果你只用到其中20个元素的空间,这无疑是浪费内存,所以OOP通过运行阶段决策可以灵活告诉程序只需要用到20个元素的空间。这里采用的方法是使用关键字new请求正确数量的内存以及使用指针来跟踪新分配的内存的位置。 ⭐在运行阶段做决策并非OOP独有的,但使用C++编写这样的代码比使用C语言更简单 ⭐(*运算符)被称为间接值(indirect value)或解除引用(dereferencing)运算符
⭐除去*运算符后则表示的是地址
小贴士 大部分C程序员会使用第一种风格,强调*xxx是int类型的值 而多数C++程序员会使用第二种风格,强调int*是一种类型 但其实没有区别 需要注意的是 int *p1,p2;这种写法是创建一个指针加一个int变量,要想创建两个指针需要都是用*
2.指针的危险 没有表明地址,指针不一定是指向存储33333的地址,这种错误会导致一些最隐匿、最难以跟踪的bug,所以程序报出了异常。
3.指针和数字 C99标准发布之前,第二种C语言是允许这样赋值的,但C++类型一致方面要求比较严格,应通过强制转换类型将数字转换为适当的地址类型(第一种)
4.使用new来分配内存 指针其实真正的用武之地在于运行阶段分配未命名的内存以存储值,C语言中可以用库函数malloc()来分配内存;C++仍然可以这么做,引入了new运算符 new int 告诉程序,需要适合存储int的内存。new运算符根据类型来确定需要多少字节的内存。然后它找到这样的内存,并返回其地址。
⭐对于指针需要指出的另一点是:new分配的内存块通常与常规变量声明分配的内存块不同,像values这些的值都存储在栈(stack)的内存区域中,而new从被称为堆(heap)或自由存储区(free store)的内存区域被分配内存
⭐计算机可能会由于没有足够的内存而无法满足new的请求。C++提供了检测并处理内存分配失败的工具。(目前而言我们仅需了解即可)
5.使用delete释放内存
需要注意的是一定要配对的使用new和delete;不然可能会发生内存泄漏(memory leak),被分配的内存再也无法使用了,如果内存泄漏严重,程序会因不断寻找更多内存而终止。 delete只能释放使用new分配的内存
6.使用new来创建动态数组 ⭐在编译时给数组分配内存被称为静态联编(static binding),意味着数组是在编译时加入到程序中的。但使用new时,如果在运行阶段需要数组,则创建它;如果不需要,则不创建。还可以在程序运行时选择数组的长度。这被称为动态联编(dynamic binding)。
①使用new创建动态数组 使用new和delete时,应当规范: ⭐不要使用delete来释放不是new分配的内存 ⭐不要使用delete释放同一个内存块两次 ⭐如果使用new[]为数组分配内存,则应使用delete[]来释放 ⭐如果使用new为一个实体分配内存,则应使用delete(没有方括号)来释放 ⭐对空指针应用delete是安全的
②使用动态数组 将指针当作数组来用,这显然有时是个问题,但这是另外一回事 你也许会问到相邻的int地址通常相差2个字节或4个字节,而*(new_pointer+1)所指向确是数组相邻的元素,它与new_pointer[1]完全等价,所以说指针算术确实是一个神奇的东西,比如*new_pointer指向一个数组
7.指针和字符串
获取独立副本
有一种情况会覆盖程序正在使用其他的内存 那么可以这么做修改 8.自动存储、静态存储、动态存储 ①在函数内部定义的常规变量使用自动存储空间,被称为自动变量(automatic variable) 例如在所属函数被调用时自动产生,在该函数结束时消亡 从上图来看,其实C++不保证新释放的内存就是下一次使用new时选择的内存。自动变量通常存储在栈中。
②静态存储 静态存储是整个程序执行期间都存在的存储方式。使变量成为静态的方式有两种:一种是在函数外面定义这个变量;另一种是在声明变量时使用关键字static 自动存储和静态存储的关键在于:这些方法严格的限制了变量的寿命。 变量可能存在于程序的整个声明周期(静态变量),也可能只是在特定函数被执行时存在(自动变量)
③动态存储 new和delete运算符提供了一种比自动变量和静态变量更灵活的方法。 它们可以管理一个内存池,这在C++中被称为自由存储空间(free store)或堆(heap)。从①的图中可以看出new和delete让你能够在一个函数中分配内存,而在另一个函数释放它,因此数据的生命周期不完全受程序或函数的生存时间控制。使用new和delete让程序员对程序如何使用内存有更大的控制权。
9.类型组合 数组+结构+指针 10.数组的替代品 ①模板类vector 模板类vector类似于string类,也是一种动态数组。是由C++98新增的标准模板库(STL)提供的。您可以在运行阶段设置vector对象的长度,可在末尾添加新数据,还可在中间插入新数据。实际上vector类确实使用new和delete来管理内存,但这种工作是自动完成的。使用时需要包含头文件vector。
②模板类array(C++11) vector类的功能比数组强大,但付出的代价是效率稍低。如果你需要的是长度固定的数组,使用数组是更佳的选择,但代价是不那么方便和安全。故C++11新增了模板类array,它也位于名称空间std中。array对象的长度是固定,是使用栈存储的,因此效率与数组相同,更方便,更安全。使用时需要包含头文件array。
以下是可行的 11.非法索引
与C语言一样,C++也不检查这种超界错误。 可以用vector和array的对象函数at()在运行期间来捕获这些非法索引,而这种检查的代价是运行时间更长,但好处在于降低意外越界错误的概率。 控制台会一闪而过,另外在之后还会提到它们的成员函数begin()和end(),这样就能够确定边界,以免无意间越界。
——————————————————————————上一篇:C++ 复合类型(三)中
——————————————————————————下一篇:C++ 循环和关系表达式(四)上