Smart Pointer智能指针
auto_ptr
在以前我们经常使用指针这个概念,指针既可以让我们精确的控制堆上的每一块内存,也让程序更加容易发生崩溃,这就让我们使用指针时必须要多加小心,所以在C++98开始便推出了auto_ptr,对裸指针进行封装,让程序员无需手动释放指针指向的内存区域,在auto_ptr生命周期结束时自动释放。
class A
{
public:
A(){cout<<"A()"<<endl;}
~A(){cout<<"~A()"<<endl;}
};
int main()
{
auto_ptr<A> pa(new A);
return 0;
}
在指针pa生命周期结束时它会自动释放。
但是auto_ptr在转移指针所有权后会产生野指针,导致程序运行时崩溃。
auto_ptr p1(new int(10));
//转移控制权
auto_ptr p2=p1;
*p1+=10;//运行时崩溃,p1为空指针,可以用p1->get判空做保护。
因此在C++11又推出了unique_ptr、shared_ptr、weak_ptr三种智能指针,慢慢取代了auto_ptr.
unique_ptr
unique_ptr与auto_ptr一样对于同一块内存只能有一个持有者,但是unique_ptr不允许赋值操作,即不能放在等号的右边(函数的参数和返回值例外),这就会避免一些操作使指针所有权转移,但是unique_ptr踢空了专门的所有权转移的方法move ,使用move可以使原unique_ptr失效,但是这样再访问原unique_ptr时会发生崩溃。
unique_ptr<int> up(new int(5));
auto up2=up;//编译报错
auto up2=move(up);
cout<<*up<<endl;//运行时崩溃,因为控制权转移,up已经失效
shared_ptr
shared_ptr允许多个该智能指针共同指向同一个对象,他通过其中的计数器来实现,计数器会记录当前有多少个shared_ptr指向同一个对象,一旦最终到达其生命周期要被销毁时,当计数器变为0的时候才会销毁该对象,使用成员函数 use count()可以观察计数器的情况。
class A
{
public:
int i;
A(int n) :i(n) { cout << "A(int)" << endl; };
~A() { cout << i << " " << "~A()" << endl; }
};
int main()
{
shared_ptr<A> sp1(new A(2)); //A(2)由sp1托管,
shared_ptr<A> sp2(sp1); //A(2)同时交由sp2托管
shared_ptr<A> sp3;
sp3 = sp2; //A(2)同时交由sp3托管
cout << sp1->i << "," << sp2->i << "," << sp3->i << endl;
A * p = sp3.get(); // get返回托管的指针,p 指向 A(2)
cout << p->i << endl; //输出 2
sp1.reset(new A(3)); // reset导致托管新的指针, 此时sp1托管A(3)
sp2.reset(new A(4)); // sp2托管A(4)
cout << sp1->i << endl; //输出 3
sp3.reset(new A(5)); // sp3托管A(5),A(2)无人托管,被delete
cout << "end" << endl;
return 0;
}
weak ptr
weak ptr的出现是为了弥补shared ptr的缺陷,因为shared ptr有一个引用成环的问题
例:
class B;
class A
{
public:
A(){ cout << "A()" << endl; };
~A() { cout << "~A()" << endl; }
shared_ptr<B> pb;
};
class B
{
public:
B() { cout << "B()" << endl; };
~B() { cout << "~B()" << endl; }
shared_ptr<A> pa;
};
int main()
{
shared_ptr<A> PA(new A);
shared_ptr<B> PB(new B);
PA->pb = PB;
PB->pa = PA;
return 0;//A和B没有析构。
}
这就是引用成环的问题。
而解决这种问题我们只需要将两个类中的一个成员变量改为weak ptr对象,而weak ptr不会增加计数器的值,所以不会造成引用成环的现象。
例
class B;
class A
{
public:
A(){ cout << "A()" << endl; };
~A() { cout << "~A()" << endl; }
weak_ptr<B> pb;
};
class B
{
public:
B() { cout << "B()" << endl; };
~B() { cout << "~B()" << endl; }
shared_ptr<A> pa;
};
int main()
{
shared_ptr<A> PA(new A);
shared_ptr<B> PB(new B);
PA->pb = PB;
PB->pa = PA;
return 0;//A和B都得以析构。
}
Lambda函数
它可以定义一个临时的函数对象,可以像其他对象一样可以传递和保存,并且最强大的是它可以访问当前函数上下文。
例:
auto add=[ ](int a,int b){return a+b;}
std::cout<<add(1,2)<<std::endl;
=后面的部分就是lambda函数,先忽略前面的[]。()里面的是参数列表,{}里面的是实现.跟普通函数基本一样。
但是这里没有返回值类型,所以系统会根据return语句进行推导,如果有多个return语句,并且类型不一样的话就会报错。
使用的方式与普通函数一样。