定义
智能指针是对象,不是指针。它是通过c++的RAII 机制实现的,主要是利用c++对象在释放资源的时候,会自动调用析构函数这一特性。
分类
auto_ptr : 智能指针,c++11已经停用;
shared_ptr : 强智能指针,可以改变资源的引用计数;
weak_ptr : 弱智能指针,不会改变资源的引用计数;
unique_ptr : 独占式强智能指针,只能转移,不能重新赋值;
智能指针的使用
shared_ptr
原理
shared_ptr 采用了引用计数器,允许多个指针指向同一个对象。每一个shared_ptr 的拷贝都指向相同的内存,并共同维护同一个引用计数器,记录统一使用被引用的次数。每增加一个shared_ptr 智能指针对象,new 对象指针的引用计数上就加1,当shared_ptr 智能指针失效时,new 对象指针的引用计数就减1。引用计数归0时,shared_ptr 会释放管理的内存空间。
shared_ptr 包含2个指针,一个是指向管理的内存空间,一个是指向内存的控制块。
内存控制块包含引用计数器,删除器,分配器等。
class Test
{
public:
Test();
~Test();
void setFather(std::shared_ptr<Test> &value) {
m_father = value;
}
void setSon(std::shared_ptr<Test> &value) {
m_son = value;
}
private:
std::shared_ptr<Test> m_father;
std::shared_ptr<Test> m_son;
};
void test() {
Test *ps = new Test();
std::shared_ptr<Test> ptr1(ps);
std::shared_ptr<Test> ptr2(ps);
ptr1->setFather(ptr2);
ptr2->setSon(ptr1);
//计数
std::cout << ptr1.use_count() << endl;
//计数
std::cout << ptr2.use_count() << endl;
//计数获取原始指针
std::cout << ptr1.get() <<endl;
std::cout << ptr2.get() <<endl;
}
输出:
Test Construct()
2
2
0xfe1740
0xfe1740
从输出信息中可以看到并未调用析构函数。主要是因为互相引用导致。
示例2 测试引用计数问题
//测试shared_ptr的引用计数
void testSharedPtrCount() {
//不要使用该方式初始化
Test *ps = new Test();
std::shared_ptr<Test> ptr1(ps);
std::shared_ptr<Test> ptr2(ps);
//计数
std::cout << ptr1.use_count() << endl;
std::cout << ptr2.use_count() << endl;
std::shared_ptr<Test> ptr3(new Test());
std::shared_ptr<Test> ptr4 = ptr3;
//计数
std::cout << ptr3.use_count() << endl;
std::cout << ptr4.use_count() << endl;
}
输出:
1
1
2
2
可以看到使用同一个对象指针初始化的时候,引用计数为1,而使用智能指针初始化智能指针后,引用计数均为2。
智能指针的头文件为:#include
weak_ptr
weak_ptr 不能单独作为智能指针使用,只能辅助shared_ptr 解决循环依赖的问题。
定义对象的时候使用shared_ptr ,引用对象的时候使用weak_ptr 。
修改shared_ptr 的代码为:
class Test
{
public:
Test();
~Test();
void setFather(std::shared_ptr<Test> &value) {
m_father = value;
}
void setSon(std::shared_ptr<Test> &value) {
m_son = value;
}
private:
//修改对象的引用为weak_ptr
std::weak_ptr<Test> m_father;
std::weak_ptr<Test> m_son;
};
输出:
Test Construct()
1
1
0x1091740
0x1091740
Test Destruct()
Test Destruct()
可以看到析构函数被调用了。(即使析构了2次,部分编译器可能不会出现析构错误信息)
unique_ptr
unique_ptr 是独占型的强智能指针。独占型就是不允许多个智能指针指向同一块内存空间,也不支持拷贝,复制。
示例1 独占性
//测试uniqueptr
void testUniquePtr() {
Test *ps = new Test();
std::unique_ptr<Test> ptr1(ps);
//编译期间就出现错误
std::unique_ptr<Test> ptr2 = ptr1;
std::cout << ptr1.get() << endl;
std::cout << ptr2.get() << endl;
}
**示例2 move **
//测试unique_ptr的转移
void testUniquePtrMove() {
Test *ps = new Test();
std::unique_ptr<Test> ptr1(ps);
std::cout << "Ptr1: " << ptr1.get() << endl;
std::unique_ptr<Test> ptr2(ps);
ptr2 = std::move(ptr1);
std::cout << "Ptr1: " << ptr1.get() << endl;
std::cout << "Ptr2: " << ptr2.get() << endl;
}
//输出
Test Construct()
Ptr1: 0x761740
Test Destruct()
Ptr1: 0
Ptr2: 0x761740
Test Destruct()
可以看出调用move() 后,ptr1 被置为nullptr (0), ptr2 被设置为0x761740 。
常见的陷阱
-
不要使用指针初始化多个智能指针。 -
不要delete get()返回的指针。
总结
- 智能指针是对象而不是指针。
- 智能指针解决的是动态内存管理的问题(堆内存)。
shared_ptr 的循环依赖问题通过weak_ptr 来解决,weak_ptr 不拥有对象的所有权,一个share_ptr 可对应多个weak_ptr 。unique_ptr 可算作auto_ptr 的翻版,不允许多个unique_ptr 持有同一个对象。auto_ptr 已经被弃用。
参考地址
C++ 智能指针
c++智能指针
C++智能指针的使用(非常详细)
C++智能指针详解
|