C++ 智能指针
指针用于存储另一个变量的地址。换句话说,指针提取了程序外部(堆内存)资源的信息。
我们使用资源的副本,并且要进行更改,是在副本上进行的。为了更改原始资源的内容,使用智能指针。
正常指针面临的问题
下面是一个描述正常指针问题的示例。
创建了一个名为 Rectangle 的类,具有两个数据成员(长度和宽度)。一个名为 fun() 的函数动态创建一个Rectangle对象。
当函数fun()结束时,对象p被销毁。由于我们没有删除p,内存仍然被分配,这个分配的资源将不可用于其他变量。
在 main() 函数中,我们执行一个无限循环,不断创建p对象并分配资源。这个问题最终导致 内存泄漏 ,而智能指针则是解决方案。
代码
#include
using namespace std;
class Rectangle { // created a class Rectangle
private:
int length; // data member as length of rectangle
int breadth; // data member as breadth of rectangle
};
void fun() // the function to indicate the problem with normal pointer
{
Rectangle* p = new Rectangle(); // Create a dynamic object p
}
int main()
{
// Infinite Loop
while (1) { // Run an infinite loop that will allocate p
fun();
}
}
注意 – 诸如JAVA、C#之类的语言具有智能地释放未使用的内存资源的垃圾回收器。
智能指针
我们将实现智能指针,以便它们可以释放未使用资源的内存。
创建一个带有指针、重载操作符 (->, *
) 和析构函数的类。
当对象超出范围时,析构函数将自动调用,并自动删除动态分配的内存。
示例
#include
using namespace std;
class SmartPtr { // Create the class to implement smart Pointer
int* ptr; // Actual pointer
public:
// Create an explicit constructor
explicit SmartPtr(int* p = NULL) { ptr = p; }
// Destructor to deallocate the resource used
~SmartPtr() { delete (ptr); }
// Overloading dereferencing operator
int& operator*() { return *ptr; }
};
int main()
{
SmartPtr ptr(new int());
*ptr = 100;
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;
}
输出
100
上述示例只适用于int类型。 我们将创建一个适用于每种数据类型的模板。
代码
#include
using namespace std;
template // Create a template class
class SmartPtr {
T* ptr; // Actual pointer
public:
// Constructor
explicit SmartPtr(T* p = NULL) { ptr = p; }
// Destructor
~SmartPtr() { delete (ptr); }
// Overloading dereferncing 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 = 100;
cout << *ptr;
return 0;
}
输出
100
智能指针的类型
- Unique_ptr
这种类型的对象仅存储一个对象。将另一个对象赋值给它时,当前对象将被解除分配。
代码:
#include
#include
using namespace std;
class Rectangle { // Create the class
// Data members
int length; // length of rectangle
int breadth; // breadth of rectangle
public:
Rectangle(int l, int b)
{ // parameterised constructor
length = l;
breadth = b;
}
int area()
{ // calculate area
return length * breadth; // return the area
}
};
int main()
{
unique_ptr P1(new Rectangle(20, 5));
cout << P1->area() << endl; // This'll print 100
// unique_ptr P2(P1);
unique_ptr P2;
P2 = move(P1);
// This'll print 100
cout << P2->area() << endl;
return 0;
}
输出
100
100
- Shared_ptr
在shared_ptr中,多个对象可以同时指向单个指针的同一个实例。使用use_count()方法来维护一个引用计数器,以便标记正在使用该对象的对象数量。
代码
#include
#include
using namespace std;
class Rectangle { // Create the class
// Data members
int length; // length of rectangle
int breadth; // breadth of rectangle
public:
Rectangle(int l, int b)
{ // parameterised constructor
length = l;
breadth = b;
}
int area()
{ // calculate area of rectangle
return length * breadth; // return area
}
};
int main()
{
shared_ptr P1(new Rectangle(20, 5)); // create shared //ptr P1
// This'll print 100
cout << P1->area() << endl;
// Create shared ptr P2
shared_ptr P2;
P2 = P1;
// This'll print 100
cout << P2->area() << endl;
// This'll now not give an error,
cout << P1->area() << endl; // prints 100
// reference counter of P2 is 2
cout << P1.use_count() << endl; // prints 2
return 0;
}
输出
100
100
100
2
- Weak_ptr
Weak_ptr与shared pointer相似。区别在于它不维护一个引用计数器,并且指针上没有对象的强引用。这个特性可能会导致死锁,因为不同的对象将会尝试持有这个指针。