1. 智能指针的作用
引入背景
C++11中引入了智能指针的概念,以便更好地管理堆内存。传统的指针容易导致以下问题:
- 堆内存泄露(忘记释放)
- 二次释放问题
- 异常处理过程中造成的内存泄露
智能指针通过RAII(资源获取即初始化)机制,能更好地管理堆内存,减少上述问题的发生。
2. 智能指针的种类
C++11版本之后,智能指针包含在 <memory>
头文件中,主要包括以下三种:
2.1 shared_ptr
多个智能指针可以共享同一个对象,该对象的生命周期由最后一个引用它的 shared_ptr
管理。shared_ptr
采用引用计数来管理对象:
- 每创建一个新的
shared_ptr
指向对象,引用计数加1。 - 每销毁一个
shared_ptr
,引用计数减1。 - 当引用计数为0时,自动删除所指向的对象。
#include <iostream>
#include <memory>
void sharedPtrExample() {
std::shared_ptr<int> p1 = std::make_shared<int>(10);
std::shared_ptr<int> p2 = p1; // 引用计数 +1
std::cout << "p1 use count: " << p1.use_count() << std::endl;
std::cout << "p2 use count: " << p2.use_count() << std::endl;
} // 离开作用域时,引用计数变为0,自动释放内存
int main() {
sharedPtrExample();
return 0;
}
2.2 unique_ptr
unique_ptr
独占其指向的对象,即同一时刻只能有一个 unique_ptr
指向给定对象。它只支持移动语义,不支持拷贝语义,以此确保其唯一性。这极大地减少了发生内存泄露的可能。
#include <iostream>
#include <memory>
void uniquePtrExample() {
std::unique_ptr<int> p1 = std::make_unique<int>(20);
std::unique_ptr<int> p2 = std::move(p1); // 转移所有权
if (p1) {
std::cout << "p1 is not null" << std::endl;
} else {
std::cout << "p1 is null" << std::endl;
}
std::cout << "p2 value: " << *p2 << std::endl;
}
int main() {
uniquePtrExample();
return 0;
}
2.3 weak_ptr
weak_ptr
是一种不控制对象生命周期的智能指针。它与 shared_ptr
协同工作,用于解决循环引用问题。weak_ptr
指向一个由 shared_ptr
管理的对象,但不会增加其引用计数。
#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 weakPtrExample() {
auto ptr1 = std::make_shared<MyClass>();
std::weak_ptr<MyClass> wptr1 = ptr1;
if (auto lck = wptr1.lock()) {
std::cout << "Object is still alive." << std::endl;
}
ptr1.reset(); // 此时对象会被销毁
if (auto lck = wptr1.lock()) {
std::cout << "Object is still alive." << std::endl;
} else {
std::cout << "Object has been deleted." << std::endl;
}
}
int main() {
weakPtrExample();
return 0;
}
3. 智能指针的初始化和赋值
智能指针是一个模板类,支持通过构造函数初始化对象:
std::shared_ptr<int> sp1 = std::make_shared<int>(1);
std::unique_ptr<int> up1 = std::make_unique<int>(2);
不能直接将原始指针赋值给智能指针:
std::shared_ptr<int> sp2(new int(3)); // 正确
// std::shared_ptr<int> sp3 = new int(4); // 错误,不能直接赋值
拷贝和赋值操作会影响引用计数:
std::shared_ptr<int> sp4 = sp1; // 引用计数增加
sp1 = std::make_shared<int>(5); // sp1转向新的对象,旧对象引用计数减少
4. unique_ptr
的使用和特性
unique_ptr
的所有权只能通过移动语义转移,不支持拷贝。
std::unique_ptr<int> up2 = std::move(up1); // 转移所有权
可以使用 reset
方法重新指定指向的对象,使用 release
方法释放所有权但不销毁对象。
up2.reset(new int(6));
int* rawPtr = up2.release();
delete rawPtr;
5. 引用计数的管理
shared_ptr
和 weak_ptr
通过引用计数来管理对象的生命周期:
shared_ptr
的拷贝和赋值增加引用计数。weak_ptr
不影响引用计数。- 当引用计数为0时,
shared_ptr
会自动释放内存。
6. weak_ptr
的应用场景
weak_ptr
可以用于打破循环引用,防止内存泄露。
class Node {
public:
std::weak_ptr<Node> next;
~Node() { std::cout << "Node destroyed" << std::endl; }
};
void createCycle() {
auto first = std::make_shared<Node>();
auto second = std::make_shared<Node>();
first->next = second;
second->next = first; // 循环引用
}
int main() {
createCycle();
return 0;
}
通过这些示例和解释,希望你能更清楚地理解和使用 C++ 智能指针,包括 shared_ptr
、unique_ptr
和 weak_ptr
的作用和用法。