12.动态内存和智能指针、 直接管理内存、shared_ptr和new结合使用

时间:2021-10-23 16:25:36

12.动态内存和智能指针

1.智能指针分为两种shared_ptr和unique_ptr,后者独占所指向的对象。智能指针也是模板,使用时要用尖括号指明指向的类型。类似emplace成员,make_shared用其参数来构造给定类型的对象。(make_shared创建一个对象并将之初始化,返回一个指向该类型的指针。

2.每个智能指针都有一个关联的计数器,称为引用计数,用来记录有多少个shared_ptr指向相同得对象3.p.use_count(),当计数值为零时,其析构函数将自动释放对象和相关联的内存。为减少资源浪费,要记得删除那些不需要的share_ptr.

4.使用动态内存的一个常见原因是允许多个对象共享相同的状态。为了实现我们所希望的数据共享,我们为每个类的对象设置一个shared_ptr来管理类。

12.1.2 直接管理内存

1.因为在*空间分配的内存是无名的,因此new 无法为其分配的对象命名,而是返回一个指向该对象的指针,若是不用delete(调用析构函数) 来操作该指针,新分配的这块内存将始终存在(即使改变指针的指向或指针失效),这就是内存泄漏问题,还有一个空悬指针问题就是在释放该内存后,未能将所有原指向该内存的所有指针置为空,而使某些指针仍指向原来那块内存。(free不调用析构函数)

2.我们可以使用直接初始化的方式来初始化一个动态分配的对象

如:int* p = new int(3);,

int *p(new int(42));

3.此外,还有默认初始化和值初始化,默认初始化的内存对象值是未定义的,而值初始化的内存对象的值是良好定义的。建议对动态分配的内存进行初始化。

int *pi = new int;                        //默认初始化,值未定义

int *pi2 = new int();      //值初始化,值是良好定义的,为0

4.我们也可以使用auto来从初始化器的值推断出我们想要分配的对象的类型int *p = new auto (3),但初始化器若是一个初始值列表时,则不能用auto来推断(因为auto推断不出来,不知道是vector还是其他的什么)

5.用new动态分配const对象是合法的:const int *pci = new const int(1024),但必须对该内存执行初始化。

6.delete p可以销毁给定指针所指向的对象,释放该对象的内存,但是delete只能对指向动态分配的内存的指针或空指针操作,否则行为未定义,另外,不能多次delete指向同一块内存的指针。

7.指向new分配的内存的指针是内置指针(普通指针),指向make_shared分配的内存的指针是智能指针。智能指针用make_shared或new的返回值来初始化。建议使用智能指针,从而避免内存泄漏和空悬指针等问题。

12.1.3 shared_ptr和new结合使用

1.不存在从普通指针到智能指针的相互转化的构造函数

2.shared_ptr<T>p(q),若q为内置指针,则应该只有两种选择new T ()或shared_ptr<T>(p);第一种是直接初始化,第二种是显示转化。

3.智能指针的初始化:shared_ptr<int> p1(new int(1024);

Shared_ptr<int> p2(make_shared<int> (2014);

Shared_ptr<int>p3 = make_shared<int> (1024);

推荐使用make_shared

4.p.reset()函数,作用是使p和参数的指向相同,会影响引用计数,所以当参数列表为空时,p = nullptr,p原来所指对象会因引用计数为0而被释放,参数列表为内置指针和智能指针时,其作用可想而知。

5.int *x(new int(1024));是危险的,因为x是一个普通指针,而不是一个智能指针。

6.当将一个shared_ptr绑定到一个普通指针时,我们就将内存的管理责任交给了这个shared_ptr。之后,我们就不应该再使用内置指针来访问那块内存了。

7.p.get()函数,返回一个和p指向相同的内置指针,同样影响引用计数,

8.判断一个shared_ptr指针是否是指向该对象的唯一指针,可以用p.unique(),但是用p.use_count() == 1没那么好。

const char *s1 = "hello world";s1是常量指针