先决条件–智能指针
C++库提供以下类型的智能指针的实现:
- auto_ptr
- unique_ptr
- shared_ptr
- weak_ptr
它们都在内存头文件中声明。
auto_ptr
从C++ 11开始不推荐使用此类模板。 unique_ptr是一种具有类似功能但具有改进的安全性的新功能。
auto_ptr是一个智能指针,用于管理通过新表达式获得的对象,并在销毁auto_ptr本身时删除该对象。
当使用auto_ptr类描述对象时,它存储指向单个已分配对象的指针,以确保当其超出范围时,它指向的对象必须自动销毁。它基于专有所有权模型,即相同类型的两个指针不能同时指向同一资源。如以下程序所示,指针的复制或分配会更改所有权,即源指针必须将所有权赋予目标指针。
// C++ program to illustrate the use of auto_ptr
#include
#include
using namespace std;
class A {
public:
void show() { cout << "A::show()" << endl; }
};
int main()
{
// p1 is an auto_ptr of type A
auto_ptr p1(new A);
p1->show();
// returns the memory address of p1
cout << p1.get() << endl;
// copy constructor called, this makes p1 empty.
auto_ptr p2(p1);
p2->show();
// p1 is empty now
cout << p1.get() << endl;
// p1 gets copied in p2
cout << p2.get() << endl;
return 0;
}
输出:
A::show()
0x1b42c20
A::show()
0
0x1b42c20
复制构造函数和auto_ptr的赋值运算符实际上并不复制存储的指针,而是将其转移,将第一个auto_ptr对象留空。这是实现严格所有权的一种方法,因此在任何给定时间只有一个auto_ptr对象可以拥有该指针,即在需要复制语义的地方不应使用auto_ptr。
为什么不建议使用auto_ptr?
它以没有两个指针都不应包含同一对象的方式获取指针的所有权。分配会转移所有权,并将右值自动指针重置为空指针。因此,由于上述无法复制,因此无法在STL容器中使用它们。
unique_ptr
std :: unique_ptr用C++ 11开发,替代了std :: auto_ptr。
unique_ptr是一种具有类似功能的新设施,但具有改进的安全性(无伪造副本分配),增加的功能(删除器)和对阵列的支持。它是原始指针的容器。它显式地防止了其复制的指针的复制,这与正常分配会发生的情况相同,即它只允许底层指针的一个所有者。
因此,当使用unique_ptr时,任何一种资源最多只能有一个unique_ptr,并且当该unique_ptr被销毁时,该资源将被自动声明。另外,由于任何资源只能有一个unique_ptr,因此任何尝试复制unique_ptr的尝试都会导致编译时错误。
但是,可以使用新的移动语义来移动unique_ptr,即使用std :: move()函数将所包含的指针的所有权转移到另一个unique_ptr。
// Works, resource now stored in ptr2
unique_ptr ptr2 = move(ptr1);
因此,当我们想要指向对象的单个指针而销毁该单个指针时将回收该对象时,最好使用unique_ptr。
// C++ program to illustrate the use of unique_ptr
#include
#include
using namespace std;
class A {
public:
void show()
{
cout << "A::show()" << endl;
}
};
int main()
{
unique_ptr p1(new A);
p1->show();
// returns the memory address of p1
cout << p1.get() << endl;
// transfers ownership to p2
unique_ptr p2 = move(p1);
p2->show();
cout << p1.get() << endl;
cout << p2.get() << endl;
// transfers ownership to p3
unique_ptr p3 = move(p2);
p3->show();
cout << p1.get() << endl;
cout << p2.get() << endl;
cout << p3.get() << endl;
return 0;
}
输出:
A::show()
0x1c4ac20
A::show()
0 // NULL
0x1c4ac20
A::show()
0 // NULL
0 // NULL
0x1c4ac20
下面的代码返回一个资源,如果我们不显式捕获返回值,该资源将被清除。如果这样做,则我们拥有该资源的专有所有权。这样,我们可以认为unique_ptr是对auto_ptr的更安全,更好的替代。
什么时候使用unique_ptr?
当您想要拥有资源的单一所有权(独占)时,请使用unique_ptr。只有一个unique_ptr可以指向一种资源。由于单个资源可以有一个unique_ptr,因此不可能将一个unique_ptr复制到另一个资源。
shared_ptr
shared_ptr是原始指针的容器。它是一个引用计数所有权模型,即它与shared_ptr的所有副本协作维护其包含的指针的引用计数。因此,每当一个新的指针指向资源时,计数器就会增加,而在调用对象的析构函数时,计数器就会减少。
引用计数:这是一种用于存储对资源(例如对象,内存块,磁盘空间或其他资源)的引用,指针或句柄数量的技术。
直到引用计数大于零(即,直到shared_ptr的所有副本都已删除),包含的原始指针引用的对象才会被销毁。
因此,当我们要将一个原始指针分配给多个所有者时,应该使用shared_ptr。
// C++ program to demonstrate shared_ptr
#include
#include
using namespace std;
class A {
public:
void show()
{
cout << "A::show()" << endl;
}
};
int main()
{
shared_ptr p1(new A);
cout << p1.get() << endl;
p1->show();
shared_ptr p2(p1);
p2->show();
cout << p1.get() << endl;
cout << p2.get() << endl;
// Returns the number of shared_ptr objects
// referring to the same managed object.
cout << p1.use_count() << endl;
cout << p2.use_count() << endl;
// Relinquishes ownership of p1 on the object
// and pointer becomes NULL
p1.reset();
cout << p1.get() << endl;
cout << p2.use_count() << endl;
cout << p2.get() << endl;
return 0;
}
输出:
0x1c41c20
A::show()
A::show()
0x1c41c20
0x1c41c20
2
2
0 // NULL
1
0x1c41c20
什么时候使用shared_ptr?
如果要共享资源所有权,请使用shared_ptr。许多shared_ptr可以指向一个资源。 shared_ptr维护此提议的参考计数。当所有shared_ptr指向资源的范围超出范围时,资源将被销毁。
weak_ptr
创建weak_ptr作为shared_ptr的副本。它提供对一个或多个shared_ptr实例拥有但不参与引用计数的对象的访问。 weak_ptr的存在或破坏对shared_ptr或其其他副本没有影响。在某些情况下,需要在shared_ptr实例之间中断循环引用。
循环依赖(shared_ptr的问题):让我们考虑一个场景,其中我们有两个类A和B,它们都具有指向其他类的指针。因此,总是像A指向B,B指向A。因此,use_count永远不会达到零,也永远不会被删除。
这就是我们使用弱指针(weak_ptr)的原因,因为它们没有引用计数。因此,声明了weak_ptr的类没有它的据点,即所有权不是共享的,但是他们可以访问这些对象。
因此,在shared_ptr由于循环依赖而导致use_count永远不会为零的情况下,使用weak_ptr可以防止这种情况,这通过将A_ptr声明为weak_ptr来解决此问题,因此,类A不拥有它,只能访问它,并且我们还需要检查对象的有效性,因为它可能超出范围。通常,这是一个设计问题。
什么时候使用weak_ptr?
当您确实要从多个位置引用对象时–对于可以忽略和取消分配的引用(因此,当您尝试取消引用时,它们只会指出对象已消失)。
参考:
https://www.quora.com/When-should-I-use-shared_ptr-and-unique_ptr-in-C++-and-what-are-they-for-for