
智能指针
(1)常见智能指针类型
(2)核心概念与行为说明
unique_ptr
独占所有权,不能复制,只能移动;
适合用于 RAII 管理资源;
默认会调用
delete
释放资源,可以自定义 deleter。
shared_ptr
采用引用计数进行资源共享;
可以复制,共享相同的底层对象
最后一个
shared_ptr
被销毁时释放资源;可以和
make_shared
搭配使用,更高效内存分配。
weak_ptr
不拥有资源,只观察 shared_ptr 所管理的对象;
用于打破
shared_ptr
之间的 循环引用;需要通过
lock()
转为shared_ptr
使用。
(3)面试常见问题及简要回答
13.1 unique_ptr
std::unique_ptr
是一个独占所有权的智能指针,它确保同一时间内只有一个指针可以拥有某个对象的所有权。适合用于一个对象只能被一个指针拥有的情况。
示例1:
#include <iostream>
#include <memory>
class MyClass {
public:
MyClass() {
std::cout << "MyClass Constructor" << std::endl;
}
~MyClass() {
std::cout << "MyClass Destructor" << std::endl;
}
void display() {
std::cout << "Display method of MyClass" << std::endl;
}
};
int main() {
// 创建一个unique_ptr对象,管理MyClass实例
std::unique_ptr<MyClass> ptr1(new MyClass());
ptr1->display(); // 使用智能指针调用方法
//类比一下vector <int> vec;
// 转移所有权
std::unique_ptr<MyClass> ptr2 = std::move(ptr1);
if (!ptr1) {
std::cout << "ptr1 is now null" << std::endl;
}
ptr2->display(); // 使用新的智能指针调用方法
// ptr2超出作用域,MyClass对象自动销毁
return 0;
}
示例2:
std::unique_ptr<int> ptr1 = std::make_unique<int>(10);
// std::unique_ptr<int> ptr2 = ptr1; // ❌ 编译错误
std::unique_ptr<int> ptr3 = std::move(ptr1); // ✅ 合法
13.2 shared_ptr
std::shared_ptr
是一个共享所有权的智能指针,可以被多个指针共享。它通过引用计数来管理对象的生命周期,当最后一个std::shared_ptr
销毁时,对象才会被释放。
#include <iostream>
#include <memory>
class MyClass {
public:
MyClass() {
std::cout << "MyClass Constructor" << std::endl;
}
~MyClass() {
std::cout << "MyClass Destructor" << std::endl;
}
void display() {
std::cout << "Display method of MyClass" << std::endl;
}
};
int main() {
// 创建一个shared_ptr对象,管理MyClass实例
std::shared_ptr<MyClass> ptr1 = std::make_shared<MyClass>();
{
// 创建第二个shared_ptr,共享相同的对象
std::shared_ptr<MyClass> ptr2 = ptr1;
ptr2->display(); // 使用智能指针调用方法
std::cout << "ptr2 going out of scope" << std::endl;
} // ptr2超出作用域,但对象未销毁,因为ptr1还在使用
ptr1->display(); // 使用剩余的智能指针调用方法
// ptr1超出作用域,MyClass对象自动销毁
return 0;
}
13.3 weak_ptr
示例1:
#include <iostream>
#include <memory>
class MyClass {
public:
std::shared_ptr<MyClass> other;
MyClass() {
std::cout << "MyClass Constructor" << std::endl;
}
~MyClass() {
std::cout << "MyClass Destructor" << std::endl;
}
void display() {
std::cout << "Display method of MyClass" << std::endl;
}
};
int main() {
std::shared_ptr<MyClass> ptr1 = std::make_shared<MyClass>();
std::shared_ptr<MyClass> ptr2 = std::make_shared<MyClass>();
// 使用weak_ptr避免循环引用
ptr1->other = ptr2;
ptr2->other = ptr1;
ptr1->display();
ptr2->display();
// ptr1和ptr2超出作用域,MyClass对象自动销毁
return 0;
}
在这个例子中,如果other
成员是std::shared_ptr
,会导致循环引用,两个对象都不会被销毁。使用std::weak_ptr
可以避免这个问题,因为它不增加引用计数。
如果要使用 std::weak_ptr
来避免循环引用,可以对 MyClass
的 other
成员使用 std::weak_ptr
,而不是 std::shared_ptr
。这样做可以防止形成循环引用,从而避免对象无法正确释放的问题。下面是修改后的示例代码:
#include <iostream>
#include <memory>
class MyClass {
public:
std::weak_ptr<MyClass> other; // 使用 weak_ptr 避免循环引用
MyClass() {
std::cout << "MyClass Constructor" << std::endl;
}
~MyClass() {
std::cout << "MyClass Destructor" << std::endl;
}
void display() {
std::cout << "Display method of MyClass" << std::endl;
}
};
int main() {
std::shared_ptr<MyClass> ptr1 = std::make_shared<MyClass>();
std::shared_ptr<MyClass> ptr2 = std::make_shared<MyClass>();
// 使用 weak_ptr 来避免循环引用
ptr1->other = ptr2;
ptr2->other = ptr1;
ptr1->display();
ptr2->display();
// ptr1 和 ptr2 超出作用域,MyClass 对象会正确释放
return 0;
}
✅说明:
std::shared_ptr<MyClass> other;
修改为std::weak_ptr<MyClass> other;
。这样做将other
成员变量改为弱引用,不会增加MyClass
对象的引用计数,也不会导致循环引用。
ptr1->other = ptr2;
和ptr2->other = ptr1;
分别将ptr2
和ptr1
赋给对方的other
成员,但是这里使用了std::weak_ptr
,因此不会导致循环引用问题。程序的输出和行为应该与之前的示例相同,即成功创建两个
MyClass
对象,并且在ptr1
和ptr2
超出作用域时,对象会被正确销毁。
示例2:
std::shared_ptr<int> sp1 = std::make_shared<int>(100);
std::shared_ptr<int> sp2 = sp1; // 引用计数 +1
std::weak_ptr<int> wp = sp1;
if (auto sp3 = wp.lock()) {
std::cout << *sp3 << std::endl;
}
13.4 总结
🧠 智能指针底层机制详解
一、shared_ptr 的实现核心
shared_ptr 由两部分组成:
资源指针(T*): 指向实际管理的对象;
控制块(Control Block): 存放引用计数信息与删除器(Deleter);
🔧 控制块内容
共享对象释放流程:
每次复制 shared_ptr,strong_count++
每次销毁 shared_ptr,strong_count--
当 strong_count 0: -> 执行 deleter 释放资源 -> 若 weak_count 0,释放控制块
二、线程安全性说明
🎯 面试进阶常问问题