本文介绍四种智能指针,
auto_ptr(C++11已弃用)、unique_ptr、shared_ptr 和 weak_ptr
智能指针作用:帮助管理资源,避免内存泄漏
auto_ptr(C++11已弃用)
虽然已弃用,但仍可使用。
先看例子
#include <iostream>
#include <memory>
using namespace std;
class myPoint{
public:
myPoint(int a)
{
cout << "myPoint的有参构造" << endl;
}
~myPoint()
{
cout << "myPoint的析构" << endl;
}
void print_out()
{
cout << Print_content << endl;
}
string Print_content;
};
void example()
{
auto_ptr<myPoint> au_smart(new myPoint(1));//利用智能指针创建一个新的对象
if(au_smart.get()) //如果智能指针不为空
{
au_smart.get()->Print_content = "hello!";
au_smart->print_out();
}
}
int main()
{
example();
return 0;
}
使用auto_ptr需要先包含memory头文件,可以通过get()获得裸指针。
从上面可以看出,我们并不用delete new 出来的myPoint了
有以下注意事项:
#include <iostream>
#include <memory>
using namespace std;
class myPoint{
public:
myPoint(int a)
{
cout << "myPoint的有参构造" << endl;
}
~myPoint()
{
cout << "myPoint的析构" << endl;
}
void print_out()
{
cout << Print_content << endl;
}
string Print_content;
};
void example1()
{
auto_ptr<myPoint> au_smart1(new myPoint(1));
if(au_smart1.get())
{
au_smart1.get()->Print_content = "haha";
auto_ptr<myPoint> au_smart2;
au_smart2 = au_smart1;//au_smart2 获得au_smart1管理的内存的所有权,au_smart1失去所有权
au_smart2->print_out();
au_smart1->print_out();
}
}
int main()
{
example1();
return 0;
}
上面这个例子编译能通过,但是运行的时候会崩溃,原因在使用
au_smart2 = au_smart1;
的时候,au_smart2已经指向au_smart1指向的地址,并且获得所有权,au_smart1无权再访问它原本所指向的内存,所以au_smart1再想访问对象的成员函数时候,就会崩溃。
如果想提前手动释放auto_ptr管理的内存,有如下方式
void example2()
{
auto_ptr<myPoint> au_smart(new myPoint(1));
if(au_smart.get())
{
delete au_smart.release();;
}
}
void example3()
{
auto_ptr<myPoint> au_smart(new myPoint(1));
if(au_smart.get())
{
myPoint * temp = au_smart.release();//release不会释放对象,归还所有权
delete temp;
}
}
//reset()方法:如果不传递参数或传递NULL,则智能指针会释放内存。
// 如果传递的是一个对象,则智能指针会释放当前对象,从而管理传递进来的对象
void example4()
{
auto_ptr<myPoint> au_smart(new myPoint(1));
if(au_smart.get())
{
au_smart.reset();//使用reset方法释放内存
}
}
shared_ptr
shared_ptr提供一个 use_count() 指针计数功能,每被引用一次,use_count()返回值+1,使用完成一次,use_count()返回值-1
shared_ptr可以使用 * 的方式获取裸指针,可以使用 get() 方法获取裸指针,或者直接使用 -> 去访问对象内容
#include <memory>
#include <iostream>
using namespace std;
class myPoint{
public:
myPoint(int a)
{
cout << "myPoint的有参构造" << endl;
}
~myPoint()
{
cout << "myPoint的析构" << endl;
}
void print_out()
{
cout << Print_content << endl;
}
string Print_content;
};
void Testshare_pointer(shared_ptr<myPoint> a)
{
a->print_out();
cout << "shared_ptr use:" << a.use_count() << endl;//每使用一次引用次数+1
}
void example()
{
shared_ptr<myPoint> shared_smart(new myPoint(1));
if(shared_smart.get())
{
shared_smart.get()->Print_content = "haha";
shared_smart->print_out();
}
cout << "shared_ptr use:" << shared_smart.use_count() << endl;
Testshare_pointer(shared_smart);
cout << "shared_ptr use:" << shared_smart.use_count() << endl;//在上面函数结束后,引用次数-1
}
int main()
{
example();
return 0;
}
上例输出结果:
myPoint的有参构造
haha
shared_ptr use:1
haha
shared_ptr use:2
shared_ptr use:1
myPoint的析构
在上述例子中,未拷贝shared_smart前,shared_smart的引用次数为1,在传进Testshare_pointer后,shared_smart的引用次数+1,当Testshare_pointer结束后,
shared_smart的引用次数-1。
shared_ptr的最佳应用场合顾名思义即是我们需要共享某对象的时候就使用它,还可以使用use_count()查看当前对象引用次数,非常方便管理
weak_ptr
weak_ptr一般与shared_ptr搭配使用,shared_ptr可以直接赋值给weak_ptr,但是shared_ptr的引用计数并不会增加,所以它的用处可以是对shared_ptr进行观察。
如基类定义一个weak_ptr用于指向子类的shared_ptr,基类可通过观察自身weak_ptr就可以知道子类是否对自身进行操作,便于管理对象
#include <memory>
#include <iostream>
using namespace std;
class myPoint{
public:
myPoint(int a)
{
cout << "myPoint的有参构造" << endl;
}
~myPoint()
{
cout << "myPoint的析构" << endl;
}
void print_out()
{
cout << Print_content << endl;
}
string Print_content;
};
void example()
{
shared_ptr<myPoint> shared_smart(new myPoint(1));
weak_ptr<myPoint> weak_smart;
cout << "shared_ptr use:" << shared_smart.use_count() << endl;
weak_smart = shared_smart;
cout << "shared_ptr use:" << shared_smart.use_count() << endl;
}
int main()
{
example();
return 0;
}
输出结果:
myPoint的有参构造
shared_ptr use:1
shared_ptr use:1
myPoint的析构
可以看出当weak_smart 指向shared_smart后,shared_smart的引用次数并没有增加。
unique_ptr
unique_ptr可以说是弃用auto_ptr的代替品,unique顾名思义某个时刻只能有一个unique_ptr指向一个给定对象,当unique_ptr被销毁时,对象也被销毁。
#include <memory>
#include <iostream>
using namespace std;
class myPoint{
public:
myPoint(int a)
{
cout << "myPoint的有参构造" << endl;
}
~myPoint()
{
cout << "myPoint的析构" << endl;
}
void print_out()
{
cout << Print_content << endl;
}
string Print_content;
};
void example()
{
unique_ptr<myPoint> unique_smart1(new myPoint(1));
cout << "Before transform: " << endl;
cout << "unique_smart1 address: " << unique_smart1.get() << endl;
unique_ptr<myPoint> unique_smart2;
cout << "unique_smart2 address: " << unique_smart2.get() << endl;
cout << endl;
cout << "After transform: " << endl;
unique_smart2 = move(unique_smart1);
cout << "unique_smart1 address: " << unique_smart1.get() << endl;
cout << "unique_smart2 address: " << unique_smart2.get() << endl;
}
int main()
{
example();
return 0;
}
输出结果:
myPoint的有参构造
Before transform:
unique_smart1 address: 0x7ab698
unique_smart2 address: 0
After transform:
unique_smart1 address: 0
unique_smart2 address: 0x7ab698
myPoint的析构
一个时刻只能有一个unique_ptr指向一个给定对象,所以当unique_smart1使用move()方法之后,unique_smart1立刻被销毁,从结果可以看到unique_smart1的地址指向了0,unique_smart2指向了unique_smart1原本指向的地址