c++基础(六)——动态内存 1. 动态内存和智能指针 2. shared_ptr 和 new 结合使用

  在我们的程序中,静态内存——用来保存局部 static 对象,类 static数据成员,以及定义在任何函数之外的变量。栈内存——用来保存定义在函数内的非 static 对象。分配在  静态内存 或 栈内存中的对象由编译器自动创建和销毁。对于栈内存,仅在其定义的程序块运行时才存在,static对象在使用之前分配,在程序结束时销毁。

  除此之外,每个程序还拥有一个内存池,这部分内存被称为*空间(堆),程序用堆来存储动态分配的对象,——即那些在程序运行时分配的对象。

  在C++中,动态内存的管理是通过一对运算符来完成的:new,在动态内存中为对象分配空间并返回一个指向该对象的指针,我们可以选择对对象进行初始化;delete,接受一个动态指针,销毁该对象,并释放与之关联的内存。

  新的标准提供了两种智能指针(smart pointer)类型来管理动态对象。shared_ptr允许多个指针指向同一个对象;unique_ptr则“独占”所指向的对象。标准库还定义了一个名为weak_ptr的伴随类,指向shared_ptr所管理的对象。这三种类型都定义在memory中。

1.1 share_ptr 类

  类似vector智能指针也是模板。

1 shared_ptr<string> p1;    //shared_ptr,可以指向string
2 shared_ptr<list<int>> p2;    //shared_ptr,可以指向int的list

  智能指针的使用方法和普通指针类似,解引用返回它指向的对象,如果在一个条件判断中使用智能指针,效果就是检测它是否为空,

1 // 如果 p1 不为空,检查它是否指向一个空 string
2 if (p1 && p1->empty()) // p->mem -- (*p).mem
3     *p1 = "ds"

1.2 make_shared 函数

  最安全的分配和使用动态内存的方法是调用一个名为make_shared的标准库函数。此函数在动态内存中分配一个对象并初始化它,返回指向此对象的shared_ptr。与智能指针一样,make_shared也定义在memory中。

1 //指向一个值为42的int的shared_ptr
2 shared_ptr<int> p3 = make_shared<int>(42);
3 //p4指向一个值为”999999999”的string
4 shared_ptr<string> p4 = make_shared<string>(10,'9');
5 //p5指向一个值初始化的int,即,值为0
6 shared_ptr<int> p5 = make_shared<int>();
7 auto p6 = make_share<vector<string>>();

  

1.3 share_ptr 的拷贝和赋值

  当进行拷贝或赋值操作时,每个shared_ptr都会记录有多少个其他shared_ptr指向相同的对象:

1 auto p = make_shared<int>(42);    //p指向的对象只有p一个引用者
2 auto q(p);    //p和q指向相同对象,此对象有两个引用者

  我们可以认为每个shared_ptr都有一个关联的计数器,通常称其为引用计数(reference count)。无论何时我们拷贝一个shared_ptr,计数器都会递增;当我们给shared_ptr赋予一个新值或是shared_ptr被销毁时,计算器就会递减。
一旦一个shared_ptr的计数器变为0,它就会自动释放自己所管理的对象

1 auto r = make_shared<int>(42);    //r指向的int只有一个引用者
2 r = q;    //给r赋值,令它指向另一个地址
3           //递增q指向的对象的引用计数
4           //递减r原来指向对象的引用计数
5           //r原来指向的对象已没有引用者,会自动释放

1.4 share_ptr 自动销毁所管理的对象

  当指向一个对象最后一个 share_ptr 被销毁时,share_ptr 类会自动销毁此对象。它是通过另一个特殊的成员函数——析构函数完成销毁工作的

2. shared_ptr 和 new 结合使用

  我们可以使用 new 返回的指针来初始化智能指针,智能指针是一个类,分装了一个原始的 C++ 指针,用以管理所指对象的生命期。

1 shared_ptr<double> p1;    //shared_ptr可以指向一个double
2 shared_ptr<int> p2(new int (42));    //p2指向一个值为42的int

  接受指针参数的智能指针构造函数是explicit的。因此,我们不能将一个内置指针隐式转换为一个智能指针,必须使用直接初始化形式来初始化一个智能指针:

1 shared_ptr<int> p1 = new int(1024);    //错误:必须使用直接初始化形式
2 shared_ptr<int> p2(new int (1024));    //正确:使用了直接初始化

  出于相同的原因,一个返回shared_ptr的函数不能在其返回语句中隐式转换一个普通指针:

1 shared_ptr<int> clone(int p){
2     return new int(p);    //错误:隐式转换为shared_ptr<int>
3 }
4 
5 shared_ptr<int> clone(int p){
6    
7     return shared_ptr<int>(new int(p)); //正确:显式地用int*创建shared_ptr<int>
8 }

  默认情况下,一个用来初始化智能指针的普通指针必须指向动态内存,因为智能指针默认使用delete释放它所关联的对象。我们可以将智能指针绑定到一个指向其他类型的资源的指针上,但是为了这样做,我们必须自己提供操作来代替  delete 。

c++基础(六)——动态内存
1. 动态内存和智能指针
2. shared_ptr 和 new 结合使用