C++ 智能指针
指针用于访问程序外的资源,如堆内存。因此,指针用于访问堆内存(如果在堆内存中创建了任何东西)。当访问资源时,我们只是使用外部资源的副本。如果我们进行任何更改,我们只需在复制的版本中更改它。然而,如果我们使用指向资源的指针,我们可以更改原始资源。
普通指针的问题
请查看下面的代码。
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对象。Rectangle由两个整数length和breadth组成。因为p是一个局部变量,当函数fun结束时,它将被销毁。然而,因为我们忘记在函数结束时使用delete p;,它消耗的内存不会被释放。这意味着内存将不能被其他资源使用。然而,我们不再需要这个变量,而是需要释放内存。
在主函数中,函数fun在一个无限循环中被调用。这意味着它将持续生成p。它将分配更多的内存,但不会释放它,因为我们没有释放它。未使用的内存无法再次使用。这会导致内存泄漏。因此,整个堆内存可能变得无用。C++11的智能指针为这个问题提供了解决方案。
智能指针正在被引入
不自觉地,没有释放指针会导致内存泄漏,这可能导致程序崩溃。Java和C#语言使用垃圾回收机制智能地释放未使用的内存,以便可以再次使用它。程序员不必担心内存泄漏。智能指针是C++11开发的一种机制。当对象被销毁时,内存也被释放。因此,我们不需要删除它,因为智能指针将处理它。
智能指针是一个包装指针的类,它有像*和->这样重载的操作符。智能指针类的对象类似于普通指针。然而,与普通指针不同,它有回收和释放被销毁对象内存的能力。
考虑一个有指针、析构函数和重载操作符的类。因为析构函数在对象退出作用域时自动调用,动态分配的内存将被删除(或引用计数可以递减)。考虑下面的SmartPtr类。
C++代码
#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可以是任何类型。点击这里了解更多有关模板的信息。
C++ 代码
#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
unique ptr 中只存储一个指针。通过将当前对象从指针中移除,我们可以赋予一个不同的对象。请注意下面的代码。首先,unique_pointer 指向 P1。然而,我们移除了 P1 并用 P2 替换它,所以指针现在指向 P2。
C++代码
#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
使用shared_ptr,多个指针可以同时指向同一个对象,并且它会使用use_count()方法来保持引用计数。
C++代码
#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
它与shared_ptr非常相似,只是它不保持引用计数。在这种情况下,指针对对象没有强引用。这样做的原因是,如果指针在请求其他对象时持有该对象,可能会形成死锁。