智能指针


静态内存及栈

  • 静态内存:局部static、类static数据成员、定义在任何函数之外的变量
  • 栈:定义在函数之内的非static对象

分配在静态内存中的对象由编译器自动创建和销毁。栈对象在其定义的程序块运行时存在。static对象在使用前分配,程序结束时销毁。


智能指针

  • s h a r e d _ p t r shared\_p tr shared_ptr : 允许多个指针指向同一个对象;
  • u n i q u e _ p t r unique\_ptr unique_ptr : 独占所指向的对象;
  • w e a k _ p t r weak\_ptr weak_ptr : 弱引用,指向 s h a r e d _ p t r shared\_ptr shared_ptr所管理的对象。

s h a r e d _ p t r shared\_ptr shared_ptr

这里写图片描述

shared_ptr<string> p1;
shared_ptr<list<int> > p2;

p1 = make_shared<string>(11, '1');// 11 个1的字符串
cout << *p1 << endl;

auto p3 = make_shared<int>();//默认0
cout << *p3 << endl;

拷贝和赋值
这里写图片描述
当指向一个对象的最后一个 s h a r e d _ p t r shared\_ptr shared_ptr被销毁时, s h a r e d _ p t r shared\_ptr shared_ptr类会通过析构函数自动销毁此对象,并释放内存。

class Node {
public:
    int a;
    Node() {
        a = 1;
    };
    ~Node() {
        cout << "********" << endl;
    }
};

int main() {
    auto pp = make_shared<Node>();
    cout << pp->a << endl;
    pp = NULL;
    cout << "2222222" << endl;
    return 0;
}
/*
输出:
1
********
2222222
*/

直接管理内存

如果提供一个括号包围的初始化器,那么可以用auto来推断想要分配的对象的类型,但是初始化器只能有一个。

auto p1 = new auto(obj);// 正确 
auto p2 = new auto{a,b,c};//错误

动态分配的 c o n s t const const对象
一个动态分配的const对象必须进行初始化。

const int *p1 = new const int(1024);
const string *p2 = new const string;

delete p1;
delete p2;

new 返回的是一个指向const的指针。
内存耗尽
内存耗尽的时候会抛出 b a d _ a l l o c bad\_alloc bad_alloc 异常。但也可以阻止

int *p1 = new (nothrow) int;//若分配失败,则返回空指针

s h a r e d _ p t r shared\_ptr shared_ptr n e w new new结合使用

我们不能将一个内置指针隐式的转化为一个智能指针。

shared_ptr<int> p1(new int(2024));

shared_ptr<int> clone(int p){
	return shared_ptr<int>(new int(p));
}

这里写图片描述
这里写图片描述
不要混合使用普通指针和智能指针
这里写图片描述
这里写图片描述
不要使用 g e t get get初始化另一个智能指针或者赋值
这里写图片描述
其他 s h a r e d _ p t r shared\_ptr shared_ptr操作

p = new int(1024);//错误
p.reset(new int(1024));//正确

reset会更新引用计数,必要时会释放对象。reset可以和unique一起使用来管理多个shared_ptr共享的对象。
if( !p.unique() )
	p.reset(new string(*p));//不是唯一用户,分配新的拷贝
*p += newVal;//现在是唯一用户,可以更改对象的值

智能指针和异常

使用自己的释放操作 d e l e t e delete delete

class Node {
public:
    int a;
    Node() {
        a = 1;
    }
    Node(int x) : a(x){}
    ~Node() {
        cout << "********" << endl;
    }
};

void endf(Node *x) {
    cout << x->a << endl;
}

int main() {
    shared_ptr<Node> p1(new Node(200),endf);
    cout << p1->a << endl;
    return 0;
}
/*
输出:
200
200
*/


class Node {
public:
    int a;
    Node() {
        a = 1;
    }
    Node(int x) : a(x){}
    //~Node() {
    //    cout << "********" << endl;
    //}
};

void endf(Node *x) {
    cout << x->a << endl;
}

int main() {
    //shared_ptr<Node> p1(new Node(200),endf);
    shared_ptr<Node> p1(new Node(200));
    cout << p1->a << endl;
    return 0;
}
/*
输出:
200
*/

u n i q u e _ p t r unique\_ptr unique_ptr

一个 u n i q u e _ p t r unique\_ptr unique_ptr拥有它所指向的对象。 u n i q u e _ p t r unique\_ptr unique_ptr不支持普通的拷贝或者赋值操作。
u n i q u e _ p t r unique\_ptr unique_ptr的一些操作:
这里写图片描述
虽然不能赋值或者拷贝,但是可以使用 r e s e t reset reset r e l e a s e release release来转移指针的所有权。

unique_ptr<string> p2(p1.release());
unique_ptr<string> p3(new string("123"));
p2.reset(p3.release());

r e l e a s e release release会切断 u n i q u e _ p t r unique\_ptr unique_ptr与之前管理的内存之间的联系,但是不会释放资源,所以需要负责释放资源

p2.release();//错误  丢失了指针
auto p = p2.release();//必须记得delete(p)

u n i q u e _ p t r unique\_ptr unique_ptr 不能拷贝的规则有一个例外:可以拷贝或者赋值一个将被销毁的 u n i q u e _ p t r unique\_ptr unique_ptr对象。
这里写图片描述
a u t o p t r auto_ptr autoptr
这里写图片描述
u n i q u e _ p t r unique\_ptr unique_ptr传递删除器
这里写图片描述

class Node {
public:
    int a;
    Node() {
        a = 1;
    }
    Node(int x) : a(x){}
    ~Node() {
        cout << "********" << endl;
    }
};

void endf(Node *x) {
    cout << x->a << endl;
}

int main() {
    //shared_ptr<Node> p1(new Node(200),endf);
    //shared_ptr<Node> p1(new Node(200));
    unique_ptr<Node,decltype(endf)*> p1(new Node(200), endf);
    cout << p1->a << endl;
    return 0;
}
/*
输出:
200
200
*/

class Node {
public:
    int a;
    Node() {
        a = 1;
    }
    Node(int x) : a(x){}
    ~Node() {
        cout << "********" << endl;
    }
};

void endf(Node *x) {
    cout << x->a << endl;
}

int main() {
    //shared_ptr<Node> p1(new Node(200),endf);
    //shared_ptr<Node> p1(new Node(200));
    //unique_ptr<Node,decltype(endf)*> p1(new Node(200), endf);
    unique_ptr<Node> p1(new Node(200));
    cout << p1->a << endl;
    return 0;
}
/*
输出:
200
********
*/

w e a k _ p t r weak\_ptr weak_ptr

w e a k _ p t r weak\_ptr weak_ptr指向一个 s h a r e d _ p t r shared\_ptr shared_ptr管理的对象,但是并不会改变其引用计数。
w e a k _ p t r weak\_ptr weak_ptr的一些操作:
这里写图片描述
使用 w e a k _ p t r weak\_ptr weak_ptr时,不能直接访问对象,必须要用 l o c k lock lock

auto p = make_shared<int>(100);
weak_ptr<int> wp(p);
if( shared_ptr<int> np = wp.lock() ){
	//---
}

一个问题:
有一个现成的约定是当我们将一个原生指针交给(具有资源所有权的)智能指针的时候,这个智能指针被允许认为自己暂时获得了这个原生指针指向资源的独占所有权。对于std::shared_ptr,分享所有权虽然是其功能之一,但如果它即将指向的资源所有权已经有人占据了,你必须让它知道资源已经被谁占了。举例:

int* p = new int();
std::shared_ptr<int> sp1(p);    //sp1认为自己独占了p指向的资源。
std::shared_ptr<int> sp2(sp1);  //sp2初始化自一个智能指针而非原
                                //生指针,其与sp1达成共识,共享
                                //了p指向的资源
std::shared_ptr<int> sp3(p);    //sp3认为自己独占了p指向的资源,
                                //但sp1和sp2还没答应共享给它
//作用域结束时,sp1、sp2和sp3指向的是同一资源,应当只销毁一次;但
//sp1和sp2不知道sp3宣称占了资源,sp3也不知道sp1和sp2宣称占了资源,
//结果该资源就会被销毁两次。多次销毁同一个资源是未定义行为。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值