C++ 智能指针

来源:互联网 发布:郭天祥单片机书籍 编辑:程序博客网 时间:2024/04/27 22:21

一,智能指针

智能指针是行为类似于指针的类对象,使用智能指针可帮助管理动态分配的内存与使用new创建的对象。


二,智能指针模板类

C++中提供的智能指针模板有auto_ptr、unique_ptr、shared_ptr和weak_ptr。可以将new获得的地址赋给智能指针对象。当智能指针过期时,其析构函数将使用delete来释放内存。因此,如果将new返回的地址赋给智能指针对象,将无需记住稍后释放这些内存,当智能指针过期时,这些内存会自动被释放。智能指针对象的很多方面都类似于常规指针,例如,可以对它执行解除引用操作(*p)、访问结构成员(p->data)、将它赋给相同类型的智能指针。但是将智能指针对象赋值个另一个智能指针对象,将引发一些问题。


三,智能指针的应用

要创建智能指针对象,必须包含头文件memory。例如,模板auto_ptr包含如下构造函数

template<class X>class auto_ptr{public:    explicit auto_ptr(X *p = 0) throw();    ...};

1,使用智能指针来管理动态分配的内存

下面是使用智能指针的例子

auto_ptr<int> pInt(new int);
下面是不使用智能指针的例子
int *p = new int;...delete p;
上面的指针变量p是一个普通的指针,当p的生命周期结束时,指针p分配的内存会被释放,但是p指向的内存空间不会被释放,因此,要手动调用delete,释放掉动态分配的内存空间。但pInt是一个智能指针,它是一个对象,当它的生命周期结束时,会调用它的析构函数,在析构函数中会释放掉动态分配的内存。
 

2,使用智能指针来管理用new创建的对象

class Resource{public:    Resource(){        cout<<"object created."<<endl;    }    ~Resource(){        cout<<"object delete."<<endl;    }};int main(){    auto_ptr<Resource> p1(new Resource);    shared_ptr<Resource> p2(new Resource);    unique_ptr<Resource> p3(new Resource);}
输出结果
object created.object delete.object created.object delete.object created.object delete.Process returned 0 (0x0) execution time : 0.039 sPress any key to continue.


3,使用智能指针应注意的问题

Resource res;auto_ptr<Resource> p1(res);

p1过期时,程序将把delete运算符用于非堆内存,这是错误的。


四,智能指针赋值与复制操作带来的问题
1,智能指针赋值带来的问题

auto_ptr<Resource> p1(new Resource);auto_ptr<Resource> p2;p2 = p1;
如果p1与p2是常规指针,则两个指针将指向同一个Resource对象。但是对于智能指针来说这是不能接受的,因为程序将试图删除同一个对象两次,一次是p1过期时,另一次是p2过期时。要避免这种问题,方法有多种:

a,建立所有权概念:对于特定的对象,只能有一个智能指针可拥有它,这样只有拥有对象的智能指针的析构函数会删除该对象。然后,让赋值操作转让所有权。这就是用于auto_ptr与unique_ptr的策略,但unique_ptr的策略更加严格。

b,创建更高智能的指针,跟踪引用特定对象的智能指针数,这称为引用计数。例如,赋值时,引用计数加1,而指针过期时,计数将减1。仅当最后一个指针过期时,才调用delete,这是shared_ptr采用的策略。

2,错误使用auto_ptr带来的问题

auto_ptr<string> p1(new string("hello world."));auto_ptr<string> p2;p2 = p1;cout<<*p2<<endl;cout<<*p1<<endl;
上面的程序在运行时会出错,出错的原因是,赋值语句p2 = p1将所有权从p1转到p2,这导致p1不再引用该字符串。在auto_ptr类型的指针放弃对象的所有权之后,便可能使用它来访问该对象,却发现这个智能指针是空的,所以会导致上面的问题。unique_ptr与auto_ptr都是采用所有权模型,如果用unique_ptr代替auto_ptr也会出错。但使用unique_ptr时,程序不会等到运行期崩溃,而在编译器发现赋值操作p2 = p1,将报错。

3,使用shared_ptr代替auto_ptr解决上面的问题
shared_ptr<string> p1(new string("hello world."));shared_ptr<string> p2;p2 = p1;cout<<*p2<<endl;cout<<*p1<<endl;

上面的程序正常运行,这次p1与p2指向同一个对象,对象的引用计数由1增加到2。在程序末尾,p2的生命周期结束时,会调用它的析构函数,此时对象的引用计数降低为1。然后p1的生命周期结束,会调用它的析构函数,此时对象的引用计数降低为0,释放掉为对象分配的内存空间。

五,unique_ptr为何优于auto_ptr?
1,unique_ptr比auto_ptr更安全
a,使用auto_ptr赋值

auto_ptr<string> p1(new string("hello world."));auto_ptr<string> p2;p2 = p1;
在上面的赋值语句中,p2接管string对象的所有权,p1的所有权将被剥夺。这样做可以防止p1与p2的析构函数试图删除同一个对象两次。但如果程序随后使用p1,这将出错。

b,使用unique_ptr赋值

unique_ptr<string> p1(new string("hello world."));unique_ptr<string> p2;p2 = p1;
编译器认为赋值语句p2 = p1非法,避免了p1不再指向有效数据的问题。因此,unique_ptr比auto_ptr更安全,编译阶段出错误比潜在的程序崩溃更安全。

2,unique_ptr可用于数组
模板auto_ptr使用delete而不是delete [],因此只能与new一起使用,而不能与new []一起使用。但unique_ptr有使用new []与 delete []版本。

unique_ptr<double []> p(new double(2));
 
六,选择智能指针的指导原则
1,如果程序需要使用多个指向同一个对象的指针,应选择使用shared_ptr。
2,如果程序不需要使用多个指向同一个对象的指针,则可使用unique_ptr。

七,weak_ptr
a,weak_ptr的作用

weak_ptr是为了配合shared_ptr而引入的一种智能指针,它更像是shared_ptr的一个助手而不是智能指针,因为它不具有普通指针的行为,没有重载operator*和->。它的最大作用在于协助shared_ptr工作,像旁观者那样观测资源的使用情况。

b,weak_ptr的用法
1,
weak_ptr被设计为与shared_ptr共同工作,可以从一个shared_ptr或者另一个weak_ptr对象构造,获得资源的观测权。但weak_ptr没有共享资源,它的构造不会引起指针引用计数的增加。
2,使用weak_ptr的成员函数use_count(),可以观测资源的引用计数。
3,使用weak_ptr的成员函数expired(),可以判断引用计数是否为0。如果引用计数为0,返回true;否则返回false。
4,使用weak_ptr一个非常重要的成员函数lock(),从被观测的shared_ptr获得一个可用的shared_ptr对象, 从而操作资源。但当expired()==true的时候,lock()函数将返回一个存储空指针的shared_ptr。

c,weak_ptr的使用

shared_ptr<int> sp(new int);weak_ptr<int> wp(sp);if (!wp.expired()){    shared_ptr<int> sp2 = wp.lock();    *sp2 = 100;}cout<<*sp2<<endl;
0 0
原创粉丝点击