12.1 Dynamic Memory and Smart Pointer(动态内存和智能指针)
全局对象在程序开始时分配·,在程序结束时摧毁。
局部和自动对象被创建和摧毁,在进入和退出定义他们的块时。
局部静态对象在第一使用前分配,在程序结束时摧毁。
智能指针保证被指向对象在合适时自动被释放。
新的库函数中定义了两种智能指针:shared_ptr和unique_ptr
前者允许多个指针指向相同对象,后者只能一对一。库函数中也定义了一个同伴类week_ptr,它利用shared_ptr实现弱引用。(三个智能指针都在memory头文件)
和vector类似,智能指针是临时的,因此我们需要提供额外的信息--指向对象的类型
默认初始化智能指针为null
当我们对shared_ptr赋值或者复制时,其他的shared_ptr和这个指针指向相同对象。
auto p = shared_ptr(42);//object has one user auto q(p)//object has p and q two users
| 操作 | 说明 |
shared_ptr<T> sp;
|
|
unique_ptr<T> up;
|
|
p
|
use p as a condition;true if p points a object |
p->mem |
synonym for (*p).mem |
p.get() |
return the (plain)pointer in p. |
swap(p, q)
|
|
p.swap(p,q)
|
一旦智能指针的计数器变为0,自动释放它所管理的内存。
- 当我们复制一个智能指针,计数器增加
- 当我们将一个智能指针作为参数传递进函数,使用它初始化另一个智能指针,从一个函数中智能指针被值返回,计数器增加1
- 当我们赋值一个新的值给智能指针(p = q--p的计数器减少1),或是当智能指针被摧毁,计数器减少1
| 操作 | 说明 |
make_shared<T>(args) |
返回一个类型为T指向动态内存的shared_ptr指针 |
p = q
|
|
p.unique()
|
如果p.use_count()是一个返回true,否则返回false |
p.use_count() |
返回对象和p共享的数量 |
如果有其他的shared_ptr指针指向内存,内存将不会释放。
vector<string> v1; { vector<string> v2 = {"hello", "world"}; v1 = v2; } //v2摧毁,v1指向内存
Blob<string> b1; { Blob<string> b2 = { "a", "an", "and" }; b1 = b2; } //b2被摧毁,b1将会指向之前b2指向的内存
当对象被摧毁时,对象的内存被摧毁。
程序尝试使用动态内存的情况:
- 当我们不知道对象需要多少内存时。
- 不知道对象需要的精确内存。
- 想要在几个对象之间分享数据。
#include <iostream> #include <string> #include <memory> #include <vector> using namespace std; class StrBlob { public: typedef vector<string>::size_type size; StrBlob(); StrBlob(initializer_list<string> li); string & front(); string & back(); void push_back(const string & str); void pop_back(); size_t ssize() { return data->size(); } private: shared_ptr<vector<string> > data; void check(size i, const string &msg); }; StrBlob::StrBlob():data(make_shared<vector<string> >()){} StrBlob::StrBlob(initializer_list<string> li):data(make_shared<vector<string> >(li)){} void StrBlob::check(size i, const string &msg) { if (i > msg.size()) throw out_of_range(msg); } string & StrBlob::front() { check(0, "Front the Word!"); return data->front(); } string & StrBlob::back() { check(0, "Back the Word!"); return this->data->back(); } void StrBlob::push_back(const string & str) { check(0, "Push_back()..."); data->push_back(str); } void StrBlob::pop_back() { check(0, "Pop_back()"); data->pop_back(); } int main() { const string s = "biubiu"; StrBlob A{ "hello! rhe", "biu", "ni" }; cout << A.back() << endl; A.push_back(s); cout << A.back() << endl; while (A.ssize() != 0) { cout << A.back() << " "; A.pop_back(); } system("PAUSE"); return 0; }
initializer_list可列表初始化(传递多个参数进行初始化)。
在使用new和delete管理动态内存中遇到的常见的三个问题:
- 忘记释放内存(delete)
- 在delete一个对象之后继续使用这个对象
- 删除同样的内存两次
能够避免上面全部的问题,通过使用智能指针。
普通指针不能转换为智能指针,智能指针可以转换为普通指针。
unique_ptr只能指向一个对象
| 操作 | 说明 |
| shared_ptr<T> p(u) | |
| shared_ptr<T> p(q, d) | q为普通指针,p指向指针对象,将会使用d代替delete释放对象 |
| shared_ptr<T> p(q2, d) | q2为shared_ptr,.. ... |
| p.reset() | 释放p |
| p.reset(q) | p指向q的对象;否则将会置空p |
不要混淆普通指针和智能指针,不要用get()去初始化或者赋值一个智能指针。
| 操作 | 说明 |
| unique_ptr<T> u1 | |
| unique_ptr<T, D> u2 | |
| unique_ptr<T, D> u(d) | |
| u = nullptr | 删除u对象;让u为null |
| u.release() | 放弃指针u已经控制的内存;将指针地址置空(00000000);返回之前控制的内存地址 |
| u.reset() | |
| u.reset(q) | |
| u.reset(nullptr) |
#include <iostream> #include <memory> #include <string> using namespace std; int main() { int a = 45; unique_ptr<int> p(new int(a)); cout << p << endl; unique_ptr<int> q(p.release()); cout << p << " and " << q << endl; p.reset(q.release()); cout << p << " and " << q << endl; system("PAUSE"); return 0; }
经常使用release来初始化或者对另一个智能指针赋值
现在的unique_ptr已经替代了auto_ptr
weak_ptr也是一个智能指针--不控制它指向对象的生存时间
绑定一个weak_ptr到shared_ptr并不影响shared_ptr的引用计数器
| 操作 | 说明 |
| weak_ptr<T> w | |
| weak_ptr<T> w(sp) | 指向和shared_ptr相同对象 |
| w =p | |
| w.reset() | 让w为null |
| w.use_count() | shared_ptr和w共享对象的数量 |
| w.expired() | 如果w.use_count()是0返回true,否则返回false |
| w.lock() | 如果w.expired()真,返回一个空的shared_ptr,否则返回一个weak_ptr指向对象的shared_ptr |

浙公网安备 33010602011771号