12.1 Dynamic Memory and Smart Pointer(动态内存和智能指针)

全局对象在程序开始时分配·,在程序结束时摧毁。

局部和自动对象被创建和摧毁,在进入和退出定义他们的块时。

局部静态对象在第一使用前分配,在程序结束时摧毁。

 

智能指针保证被指向对象在合适时自动被释放。

 

新的库函数中定义了两种智能指针:shared_ptrunique_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.
if smart point p delete the object, the point will disappear.
 
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指向的内存

 

当对象被摧毁时,对象的内存被摧毁。

 

程序尝试使用动态内存的情况:

  1. 当我们不知道对象需要多少内存时。
  2. 不知道对象需要的精确内存。
  3. 想要在几个对象之间分享数据。

 

#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管理动态内存中遇到的常见的三个问题:

  1. 忘记释放内存(delete)
  2. 在delete一个对象之后继续使用这个对象
  3. 删除同样的内存两次

 

能够避免上面全部的问题,通过使用智能指针。

 

普通指针不能转换为智能指针,智能指针可以转换为普通指针。

 

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
posted @ 2018-11-23 22:00  Hk_Mayfly  阅读(327)  评论(0)    收藏  举报