智能指针讲解
写重载取地址运算符发现的好例子,干脆单独写一篇来讲
1. 什么是智能指针?
智能指针是 C++ 标准库提供的一种类模板,它封装了原始指针并提供了自动管理内存的功能,避免了手动管理内存(new
和 delete
)时容易出现的错误,如内存泄漏和野指针等问题。
2. std::unique_ptr
std::unique_ptr
是一种 独占所有权 的智能指针,它表示一个指针拥有一个资源的所有权,并且资源的所有权不能被共享。 std::unique_ptr
在其生命周期结束时会自动释放资源。
特点:
- 不能被复制:
unique_ptr
只能通过移动(std::move
)来转移所有权。 - 自动释放资源:当
unique_ptr
被销毁时,它会自动释放其指向的资源。
#include <iostream>
#include <memory> // 包含 unique_ptr
class MyClass {
public:
MyClass() { std::cout << "MyClass Constructor!" << std::endl; }
~MyClass() { std::cout << "MyClass Destructor!" << std::endl; }
void display() {
std::cout << "Hello from MyClass!" << std::endl;
}
};
int main() {
// 使用 unique_ptr 管理 MyClass 对象
std::unique_ptr<MyClass> ptr1 = std::make_unique<MyClass>();
// 调用成员函数
ptr1->display();
// 在这里 ptr1 被销毁,自动调用析构函数,释放 MyClass 对象
return 0;
}
std::unique_ptr<MyClass> ptr1 = std::make_unique<MyClass>();
:std::make_unique
用来创建一个unique_ptr
并初始化它,ptr1
拥有这个MyClass
对象的所有权。- 当
ptr1
离开作用域时,它会自动释放内存,调用MyClass
的析构函数。
你可以看到,unique_ptr
保证了 MyClass
对象在不再使用时会被自动销毁。
注意:
- 不能复制
unique_ptr
,只能转移所有权。反例如下面代码
std::unique_ptr<MyClass> ptr2 = ptr1; // 编译错误,不能复制 unique_ptr
不过你可以使用 std::move
转移所有权:
std::unique_ptr<MyClass> ptr2 = std::move(ptr1); // 正确,ptr1 的所有权被转移给 ptr2
3. std::shared_ptr
std::shared_ptr
是一种 共享所有权 的智能指针,它允许多个 shared_ptr
对象共同拥有同一个资源。资源会被自动释放,当所有指向资源的 shared_ptr
被销毁时,资源才会被释放。
特点:
- 共享所有权:多个
shared_ptr
可以指向同一个资源。 - 引用计数:
shared_ptr
内部维护一个引用计数,记录有多少个shared_ptr
指向同一个对象。当引用计数为 0 时,资源才会被销毁。 - 线程不安全:引用计数的增加和减少不是线程安全的,如果需要跨线程使用,需要自行加锁。
#include <iostream>
#include <memory> // 包含 shared_ptr
class MyClass {
public:
MyClass() { std::cout << "MyClass Constructor!" << std::endl; }
~MyClass() { std::cout << "MyClass Destructor!" << std::endl; }
void display() {
std::cout << "Hello from MyClass!" << std::endl;
}
};
int main() {
// 使用 shared_ptr 管理 MyClass 对象
std::shared_ptr<MyClass> ptr1 = std::make_shared<MyClass>();
// 共享 ptr1 的所有权
std::shared_ptr<MyClass> ptr2 = ptr1;
std::cout << "Reference count: " << ptr1.use_count() << std::endl; // 输出 2
// 调用成员函数
ptr1->display();
ptr2->display();
std::cout << "Reference count: " << ptr1.use_count() << std::endl; // 输出 2
return 0;
}
std::shared_ptr<MyClass> ptr1 = std::make_shared<MyClass>();
:创建一个shared_ptr
,它管理一个MyClass
对象。std::shared_ptr<MyClass> ptr2 = ptr1;
:ptr2
共享了ptr1
所指向的MyClass
对象,两者都有对该对象的所有权。ptr1.use_count()
返回引用计数,表示当前有多少个shared_ptr
指向同一个对象。
可以看到,当多个 shared_ptr
共享对同一个资源的所有权时,引用计数在 use_count()
调用时显示为 2。当 shared_ptr
对象 ptr1
和 ptr2
都超出作用域时,MyClass
对象的析构函数会被调用。
4. std::weak_ptr
std::weak_ptr
是一种弱引用智能指针,通常与 std::shared_ptr
配合使用。它不参与引用计数的增加或减少,避免了循环引用问题。weak_ptr
用于观察一个 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 << "Hello from MyClass!" << std::endl; }
};
int main() {
std::shared_ptr<MyClass> ptr1 = std::make_shared<MyClass>();
std::weak_ptr<MyClass> weakPtr = ptr1; // weak_ptr 观察 ptr1
std::cout << "Reference count: " << ptr1.use_count() << std::endl; // 输出 1
if (auto sharedPtr = weakPtr.lock()) { // lock() 返回一个 shared_ptr
sharedPtr->display(); // 如果 weak_ptr 指向的对象仍然存在,使用它
} else {
std::cout << "Object no longer exists!" << std::endl;
}
return 0;
}
std::weak_ptr<MyClass> weakPtr = ptr1;
:weakPtr
是对ptr1
管理的对象的弱引用,不增加引用计数。weakPtr.lock()
:lock()
尝试将weak_ptr
转换为shared_ptr
。如果对象已经被销毁,lock()
返回nullptr
,否则返回一个有效的shared_ptr
。
做个总结吧
std::unique_ptr
:表示独占所有权,不能复制,只能通过std::move
转移所有权,自动管理资源。std::shared_ptr
:表示共享所有权,多个shared_ptr
可以共同拥有一个资源,引用计数机制保证资源的自动释放。std::weak_ptr
:不增加引用计数,避免循环引用问题,用于观察和访问由shared_ptr
管理的资源。
智能指针提供了安全、自动管理内存的方式,帮助避免了手动管理内存时可能出现的错误,如内存泄漏、双重释放等。尤其是在现代 C++ 编程中,智能指针是一个非常强大的工具,能够大大简化内存管理。