START
Hi,大家好!今天我们来聊一聊C++中的智能指针。
在谈到学习C++时,好多人都说它特别难,说它复杂。很可能有一部分原因就是C++的内存管理,在程序运行过程中很容易就会出现内存泄漏。然而从C++11引入的智能指针这一问题得到解决。
C++11引入了三种智能指针:
unset
unset
1、std::shared_ptr
unset
unset
std::shared_ptr
是用于管理动态分配的资源,实现自动内存管理。它是一个引用计数型智能指针,允许多个
shared_ptr
对象共享同一块动态分配的内存,并在不再需要时自动释放。
以下是
std::shared_ptr
的一些重要特点和用法:
-
引用计数:
std::shared_ptr
使用引用计数来跟踪共享的资源的使用情况。每个
std::shared_ptr
对象都包含一个计数器,记录有多少个
std::shared_ptr
对象共享同一块内存。
-
安全性:
std::shared_ptr
通过引用计数机制来确保在所有持有该资源的
std::shared_ptr
对象被销毁后,资源会被释放。这避免了内存泄漏和空悬指针等问题。
-
拷贝和赋值:
std::shared_ptr
支持拷贝和赋值操作,当进行拷贝时,计数器会增加;当进行销毁或重新赋值时,计数器会减少。当计数器减少到 0 时,资源会被释放。
-
动态分配的资源:
std::shared_ptr
通常用于管理动态分配的资源,如内存、文件句柄等。它不仅可以管理指针指向的内存,还可以管理自定义的资源,如自定义的释放器等。
-
线程安全性:
std::shared_ptr
在多线程环境下是线程安全的,可以被多个线程同时访问和操作,不需要额外的同步机制。
使用
std::shared_ptr
可以有效地管理动态分配的资源,避免内存泄漏和空悬指针等问题,并且可以方便地进行资源的共享和传递。然而,要注意避免循环引用的问题,这可能导致资源无法释放。通常可以使用
std::weak_ptr
来解决循环引用的问题。
下面来看一个使用
std::shared_ptr
的简单示例:
#include
#include
class MyClass {
public:
MyClass() {
std::cout <"Constructor" endl;
}
~MyClass() {
std::cout <"Destructor" endl;
}
void doSomething() {
std::cout <"Doing something..." endl;
}
};
int main() {
// 创建一个动态分配的 MyClass 对象,并用 shared_ptr 管理
std::shared_ptr ptr1(new MyClass);
// 创建另一个 shared_ptr,与 ptr1 共享同一块内存
std::shared_ptr ptr2 = ptr1;
// 使用箭头运算符访问对象成员函数
ptr1->doSomething();
// 当 ptr1 和 ptr2 被销毁时,资源会被自动释放
return 0;
}
在这个示例中,我们首先创建了一个动态分配的
MyClass
对象,并用
std::shared_ptr
管理它。然后,我们创建了另一个
std::shared_ptr
,与第一个
std::shared_ptr
共享同一块内存。这意味着两个
std::shared_ptr
对象共享同一个计数器和同一块内存。最后,我们通过箭头运算符访问了
MyClass
对象的成员函数,并且在程序结束时,由于
ptr1
和
ptr2
被销毁,
MyClass
对象的资源会被自动释放。
这个示例展示了
std::shared_ptr
的基本用法,包括对象的创建、拷贝、访问成员函数以及自动资源管理。
unset
unset
2、std::weak_ptr
unset
unset
std::weak_ptr
是用于解决
std::shared_ptr
的循环引用问题。
std::weak_ptr
允许共享资源但不拥有它,它是
std::shared_ptr
的弱引用。
与
std::shared_ptr
不同,
std::weak_ptr
并不增加引用计数,因此它不会影响资源的生命周期。当最后一个
std::shared_ptr
指向的资源被释放后,所有相关联的
std::weak_ptr
对象都会自动失效,指向空指针。
以下是
std::weak_ptr
的一些重要特点和用法:
-
弱引用:
std::weak_ptr
是一个弱引用,它不增加资源的引用计数,因此不会影响资源的生命周期。
-
共享资源:
std::weak_ptr
允许与
std::shared_ptr
共享同一块内存,但不拥有它。它通常用于解决循环引用的问题,防止资源无法释放。
-
检查是否有效:
可以使用
std::weak_ptr
的
expired()
方法来检查与之关联的资源是否有效。如果资源已经释放,则
expired()
返回
true
,否则返回
false
。
-
获取强引用:
可以使用
std::weak_ptr
的
lock()
方法来获取与之关联的资源的强引用(即
std::shared_ptr
对象)。如果资源仍然有效,则
lock()
返回一个有效的
std::shared_ptr
;如果资源已经释放,则返回一个空的
std::shared_ptr
。
以下是一个示例,展示了
std::weak_ptr
的基本用法:
#include
#include
class MyClass {
public:
MyClass() {
std::cout <"Constructor" endl;
}
~MyClass() {
std::cout <"Destructor" endl;
}
};
int main() {
std::shared_ptr sharedPtr = std::make_shared();
std::weak_ptr weakPtr = sharedPtr;
// 检查 weakPtr 是否有效
if (!weakPtr.expired()) {
// 获取强引用
std::shared_ptr strongPtr = weakPtr.lock();
if (strongPtr) {
// 访问资源
std::cout <"Resource is valid." endl;
}
}
// sharedPtr 被销毁,资源释放
sharedPtr.reset();
// 再次检查 weakPtr 是否有效
if (weakPtr.expired()) {
std::cout <"Resource is expired." endl;
}
return 0;
}
在这个示例中,我们首先创建了一个
std::shared_ptr
来管理动态分配的资源,然后创建了一个
std::weak_ptr
对象与之共享同一块内存。我们使用
expired()
方法检查了
std::weak_ptr
是否有效,并使用
lock()
方法获取了与之关联的资源的强引用。最后,我们释放了
sharedPtr
,并再次检查了
std::weak_ptr
是否有效。
通过使用
std::weak_ptr
,我们可以解决
std::shared_ptr
的循环引用问题,确保资源能够正确释放,避免内存泄漏。
unset
unset
3、std::unique_ptr
unset
unset
std::unique_ptr
是用于管理动态分配的资源。与
std::shared_ptr
不同,
std::unique_ptr
是独占所有权的智能指针,即一个
std::unique_ptr
对象独占一个动态分配的资源,并负责在其生命周期结束时释放该资源。
以下是
std::unique_ptr
的一些重要特点和用法:
-
独占所有权:
std::unique_ptr
是独占所有权的智能指针,一次只能有一个
std::unique_ptr
对象拥有一个动态分配的资源。
-
资源所有权转移:
std::unique_ptr
支持资源所有权的转移。可以通过
std::move
函数将一个
std::unique_ptr
对象的所有权转移到另一个对象。