0.使用普通指针带来的问题
c++ 的内存管理是一个让人非常头疼的问题,当我们写一个new语句时,如果没有写响应的delete语句,就会造成内存泄漏的问题。或者就算我们写了delete语句,有可能程序还没有执行到delete语句就返回或者跳转到其他的语句,一样会造成内存泄漏。看下面这个例子
void test()
{
double *p = new double;
*p = 5.5;
return;
}
执行这个函数,到第一条语句的时候,在栈内存中分配了一个4字节的内存存储指针p(假设我们的系统是32位的),在堆中申请了一个8字节的内存存储一个double类型。指针p指向double类型的首地址。执行到return的时候,栈中p占用的内存会被释放,但是堆中的内存不会被释放。这就造成了内存泄漏的问题。如果在函数末尾,p被释放的时候,p所指向的内存也能够被释放掉,那该有多好。但是,很可以,p只是换一个普通的指针,不是具有析构函数的对象。如果它是对象,则可以在对象过期的时候,调用析构函数删除它指向的内存。这个其实就是c++中智能指针干的事情。c++提供了三种方案来解决这个问题,auto_ptr、unique_ptr、shared_ptr。模板auto_ptr是c++98提供的方案,已经被c++11抛弃,并且提供了另外两种替代方案。
1. 使用智能指针
先来看一个例子,如何使用智能指针
#include<iostream>
#include<memory>
#include<string>
using namespace std;
class report {
private:
string str;
public:
report(const string s):str(s) {
cout<<"create obj"<<endl;
}
~report() {
cout<<"destroy"<<endl;
}
void comment() const {
cout<<str<<endl;
}
};
int main()
{
{
auto_ptr<report> p(new report("auto_ptr"));
p->comment();
}
{
shared_ptr<report> p(new report("shared_ptr"));
p->comment();
}
{
unique_ptr<report> p(new report("unique_ptr"));
p->comment();
}
return 0;
}
执行编译指令
g++ -g pointer.cpp -std=c++11
运行结果如下:
create obj
auto_ptr
destroy
create obj
shared_ptr
destroy
create obj
unique_ptr
destroy
所有智能指针都有一个excplicit构造函数,这个构造函数将指针作为参数,自动将指针转换为智能指针类型。
template<class X>class auto_ptr {
public:
explicit auto_ptr(X* p = 0) throw();
···
};
下面几种赋值有的合法有的不合法
shared_ptr<double> pd;
double *p = new double();
pd = p ; //不允许
pd = shared_prt<double>(p);// 显式转换,允许
shared_prt<double> q = p; //不允许
share_ptr<double> q(p); //允许
智能指针要注意的一点
string a("hello,world");
shared_ptr<string> p(&a); //错误!!
p指针过期时,程序将delete运算符用于非堆内存,这是错误的。
2. auto_ptr、shared_ptr、unique_ptr的区别
- 一个auto_ptr赋值给另外一个auto_ptr,会转交所有权,同时自己变成空指针。对于某一个特定的对象,只有一个auto_ptr指针可以拥有它,这样,只有拥有这个对象的指针才能删除该对象。unique_ptr也是采取这种所有权转让的策略,只是更加严格。
auto_ptr<string> p, q;
p =auto_ptr(new string("test"));
q = p ; // 允许,q拥有控制权,p变成空指针
例子
int main()
{
auto_ptr<string> p[3] =
{
auto_ptr<string>(new string("A")),
auto_ptr<string>(new string("B")),
auto_ptr<string>(new string("C"))
};
auto_ptr<string> ap;
ap = p[2]; //ap拥有控制权,p[2]变成空指针
for(int i = 0; i < 3; i++) {
cout << *p[i]<<endl;
}
cout<<"-----"<<endl;
cout<<*ap<<endl;
return 0;
}
程序输出结果:
A
B
Segmentation fault //打印p[2]程序崩溃
- unique_ptr不允许将一个指针赋值给另外一个指针,除非是函数返回一个指针然后赋值给另外一个指针
unique_ptr<string> createstring() ;
unique_ptr<string> p, q;
p = unique_ptr(new string("zhengk"));
p = q ;//不允许,编译不通过
p = createstring(); //允许
例子
#include<iostream>
#include<memory>
#include<string>
using namespace std;
unique_ptr<string> createstring()
{
unique_ptr<string> p;
p = unique_ptr<string>(new string("zhengkang"));
return p;
}
int main()
{
unique_ptr<string> p[3] =
{
unique_ptr<string>(new string("A")),
unique_ptr<string>(new string("B")),
unique_ptr<string>(new string("C"))
};
unique_ptr<string> ap;
for(int i = 0; i < 3; i++) {
cout << *p[i]<<endl;
}
cout<<"-----"<<endl;
ap = createstring();
cout<<*ap<<endl;
return 0;
}
编译运行结果:
A
B
C
-----
zhengkang
- shared_ptr 采用引用计数策略,shared_ptr跟踪引用特定对象的智能指针数。赋值时,指针计数加1,指针过期时,计数减1。仅当最后一个指针过期时,调用delete。