C++ 智能指针
指针用于访问程序之外的资源,如堆内存。因此,指针被用于访问堆内存(如果在堆内存中创建了任何东西)。在访问任何外部资源时,我们只需使用它的副本。如果要进行任何更改,只需在复制的版本中更改即可。但是,如果使用指向资源的指针,则可以更改原始资源。
普通指针的问题
查看下面的代码。
#include
using namespace std;
class Rectangle {
private:
int length;
int breadth;
};
void fun()
{
// By taking a pointer p and
// dynamically creating object
// of class rectangle
Rectangle* p = new Rectangle();
}
int main()
{
// Infinite Loop
while (1) {
fun();
}
}
函数fun生成一个指向Rectangle对象的指针。矩形由两个整数组成:长和宽。因为p是一个局部变量,它将在函数结束时被销毁。但是,因为我们忘了使用delete p;在函数结束时,它所消耗的内存将不会被释放。这意味着内存将不能被其他资源使用。但是,我们不再需要变量,而是需要内存。
Fun在main函数的无限循环中被调用。这意味着它将继续生成p。它将分配更多的内存,但不会释放它,因为我们没有释放它。未使用的内存不能再次使用。这将导致内存泄漏。因此,整个堆内存可能变得无用。c++ 11的一个特性——智能指针(Smart Pointer)为这个问题提供了一个解决方案。
智能指针正在被引入
不知不觉中,不处理指针的定位会导致内存泄漏,从而可能导致程序崩溃。垃圾收集机制在Java和c#语言中被用于智能地释放未使用的内存,以便再次使用它。程序员不必担心内存泄漏。智能指针是c++ 11开发的一种机制。当对象被销毁时,内存也被释放。因此,我们不需要删除它,因为Smart Pointer会处理它。
Smart Pointer是一个指针包装类,重载了*和->等操作符。智能指针类的对象类似于普通指针。然而,与普通指针不同的是,它有释放和释放已销毁对象内存的能力。
接受一个具有指针、析构函数和重载操作符(如*和->)的类。因为析构函数是在对象退出作用域时自动调用的,动态分配的内存将被删除(或者引用计数可以减少)。考虑下面所示的SmartPtr类。
#include
using namespace std;
class SmartPtr {
int* ptr; // Actual pointer
public:
// for use of explicit keyword
explicit SmartPtr(int* p = NULL) { ptr = p; }
// Destructor
~SmartPtr() { delete (ptr); }
// Overloading dereferencing operator
int& operator*() { return *ptr; }
};
int main()
{
SmartPtr ptr(new int());
*ptr = 20;
cout << *ptr;
// We don't need to call delete ptr: when the object
// ptr goes out of scope, the destructor for it is automatically
// called and destructor does delete ptr.
return 0;
}
输出:
20
这只适用于int。所以我们需要为每个对象创建一个智能指针?不,模板,有办法。从下面的代码中可以看到,T可以是任何类型。
#include
using namespace std;
// A generic smart pointer class
template
class SmartPtr {
T* ptr; // Actual pointer
public:
// Constructor
explicit SmartPtr(T* p = NULL) { ptr = p; }
// Destructor
~SmartPtr() { delete (ptr); }
// Overloading dereferencing operator
T& operator*() { return *ptr; }
// Overloading arrow operator so that
// members of T can be accessed
// like a pointer (useful if T represents
// a class or struct or union type)
T* operator->() { return ptr; }
};
int main()
{
SmartPtr ptr(new int());
*ptr = 20;
cout << *ptr;
return 0;
}
输出:
20
注意: 智能指针还可以用于管理资源,如文件句柄或网络套接字。
智能指针类型
1. unique ptr
只有一个指针存储在唯一的ptr中。通过从指针中移除当前对象,我们可以给一个不同的对象赋值。请注意下面的代码。首先,unique_pointer指向P1。但是,我们移除P1,用P2替换它,所以指针现在指向P2。
#include
using namespace std;
#include
class Rectangle {
int length;
int breadth;
public:
Rectangle(int l, int b){
length = l;
breadth = b;
}
int area(){
return length * breadth;
}
};
int main(){
unique_ptr P1(new Rectangle(10, 5));
cout << P1->area() << endl; // This'll print 50
// unique_ptr P2(P1);
unique_ptr P2;
P2 = move(P1);
// This'll print 50
cout << P2->area() << endl;
// cout<area()<
输出:
50
50
2. shared_ptr
使用共享ptr,多个指针可以同时指向同一个对象,它将使用use count()方法保持一个引用计数器。
#include
using namespace std;
#include
class Rectangle {
int length;
int breadth;
public:
Rectangle(int l, int b)
{
length = l;
breadth = b;
}
int area()
{
return length * breadth;
}
};
int main()
{
shared_ptr P1(new Rectangle(10, 5));
// This'll print 50
cout << P1->area() << endl;
shared_ptr P2;
P2 = P1;
// This'll print 50
cout << P2->area() << endl;
// This'll now not give an error,
cout << P1->area() << endl;
// This'll also print 50 now
// This'll print 2 as Reference Counter is 2
cout << P1.use_count() << endl;
return 0;
}
输出:
50
50
50
2
3. weak_ptr
它非常类似于共享ptr,除了它不保留引用计数器。在这种情况下,指针不会在对象上有据点。这样做的原因是,如果指针在请求其他对象时持有该对象,它们可能会形成死锁。