欢迎来到Cefler的博客😁
🕌博客主页:那个传说中的man的主页
🏠个人专栏:题目解析
🌎推荐文章:题目大解析(3)
目录
- 👉🏻为什么需要智能指针?
- [👉🏻 内存泄漏](#👉🏻 内存泄漏)
- 👉🏻智能指针的使用及原理
- 👉🏻C++标准库提供的常见智能指针
👉🏻为什么需要智能指针?
没有智能指针时,开发人员需要手动管理动态内存分配和释放。这可能导致以下问题:
-
内存泄漏:手动管理内存很容易出现内存泄漏,即程序在不再需要使用某块动态分配的内存时未能释放它,导致系统中有大量无法访问的内存块,最终耗尽内存资源。
-
悬空指针:手动释放内存后,如果忘记将指针置空,就会产生悬空指针,即指向已经释放的内存的指针,当再次使用这个指针时会导致程序崩溃或者不可预期的行为。
-
多重释放:同一块内存被释放多次,可能会破坏内存结构,导致程序崩溃。
-
资源泄漏:除了内存外,还存在其他资源(如文件句柄、数据库连接等)需要手动管理,容易出现类似的泄漏和错误。
智能指针通过封装了动态分配的内存,并提供自动的内存管理机制,可以有效地解决上述问题。当智能指针超出作用域时,它所管理的资源会被自动释放,从而避免了内存泄漏和悬空指针等问题。此外,智能指针的引入也提高了代码的可读性和可维护性,减少了手动管理内存带来的麻烦,使得程序更加健壮和安全。
因此,智能指针是现代C++编程中推荐的一种重要工具,它能够简化内存管理并提高代码的安全性。
👉🏻 内存泄漏
什么是内存泄漏,内存泄漏的危害
- 什么是内存泄漏:内存泄漏指因为疏忽或错误造成程序未能释放已经不再使用的内存的情况。内存泄漏并不是指内存在物理上的消失,而是应用程序分配某段内存后,因为设计错误,失去了对该段内存的控制,因而造成了内存的浪费。
- 内存泄漏的危害:长期运行的程序出现内存泄漏,影响很大,如操作系统、后台服务等等,出现内存泄漏会导致响应越来越慢,最终卡死。
内存泄漏分类
堆内存泄漏(Heap leak)
堆内存指的是程序执行中依据须要分配通过malloc / calloc / realloc / new等从堆中分配的一
块内存,用完后必须通过调用相应的 free或者delete 删掉。假设程序的设计错误导致这部分
内存没有被释放,那么以后这部分空间将无法再被使用,就会产生Heap Leak。系统资源泄漏
指程序使用系统分配的资源,比方套接字、文件描述符、管道等没有使用对应的函数释放
掉,导致系统资源的浪费,严重可导致系统效能减少,系统执行不稳定。
如何避免内存泄漏
- 工程前期良好的设计规范,养成良好的编码规范,申请的内存空间记着匹配的去释放。ps:
这个理想状态。但是如果碰上异常时,就算注意释放了,还是可能会出问题。需要下一条智
能指针来管理才有保证。 - 采用
RAII思想
或者智能指针来管理资源。 - 有些公司内部规范使用内部实现的私有内存管理库。这套库自带内存泄漏检测的功能选项。
- 出问题了使用内存泄漏工具检测。ps:不过很多工具都不够靠谱,或者收费昂贵。
内存泄漏非常常见,解决方案分为两种:1、事前预防型。如
智能指针
等。2、事后查错型。如泄 漏检测工具
。
👉🏻智能指针的使用及原理
RAII思想
RAII(Resource Acquisition Is Initialization)是一种C++编程中的重要设计模式,它利用对象的生命周期来管理资源的获取和释放,从而确保资源在适当的时候被正确地释放。RAII是C++语言中的一种重要特性,也是使用智能指针等资源管理类的基础理念。
RAII的核心思想可以简单概括为:在对象的构造函数中获得资源 ,在对象的析构函数中释放资源。通过这种方式,可以确保在任何情况下(包括异常情况),资源都能够得到正确的释放,从而避免了资源泄漏等问题。
🧁RAII的优点包括:
- 资源自动管理:通过对象的生命周期来管理资源,使得资源的获取和释放变得自动化,避免了手动管理资源带来的麻烦。
- 异常安全:即使在发生异常的情况下,资源也能够被正确释放,不会造成资源泄漏。
- 代码清晰:RAII可以提高代码的可读性和可维护性,因为资源管理的逻辑被封装在对象的构造和析构函数中,使得代码更加清晰简洁。
在实际编程中,RAII常常与智能指针
、文件句柄
、数据库连接
等资源管理类一起使用,以确保资源的正确管理。同时,开发人员也可以通过自定义类来实现RAII,将资源管理逻辑封装在对象的构造和析构函数中,从而实现对任意类型资源的自动化管理。
总的来说,RAII是C++中一种强大且灵活的资源管理机制,能够帮助开发人员避免资源泄漏等问题,提高代码的稳定性和可靠性。
以下是一个采用RAII思想的例子:
cpp
// 使用RAII思想设计的SmartPtr类
template<class T>
class SmartPtr {
public:
SmartPtr(T* ptr = nullptr)
: _ptr(ptr)
{}
~SmartPtr()
{
if(_ptr)
delete _ptr;
}
private:
T* _ptr;
};
int div()
{
int a, b;
cin >> a >> b;
if (b == 0)
throw invalid_argument("除0错误");
return a / b;
}
void Func()
{
ShardPtr<int> sp1(new int);
ShardPtr<int> sp2(new int);
cout << div() << endl;
}
int main()
{
try {
Func();
}
catch(const exception& e)
{
cout<<e.what()<<endl;
}
return 0;
}
智能指针的原理
智能指针是C++语言中用于管理动态内存的类模板,其原理基于RAII(Resource Acquisition Is Initialization)设计模式。智能指针的核心思想是利用对象的生命周期来管理动态分配的内存,以确保在适当的时机释放内存,避免内存泄漏和悬空指针等问题。
智能指针的原理可以简单概括如下:
-
封装指针 :智能指针通过封装原始的裸指针(raw pointer),并提供对应的操作符重载和成员函数,实现对动态分配内存的访问和管理。
-
计数引用:智能指针通常会记录当前指向的内存块被多少个智能指针共享,这就是所谓的引用计数。引用计数的增加和减少是通过智能指针的拷贝构造和析构函数来完成的。
-
析构函数自动释放:当一个智能指针超出其作用域时,其析构函数会自动被调用,从而触发对应的内存释放操作。如果这个智能指针是唯一指向某块内存的指针,并且没有发生深度拷贝,那么内存将被正确释放。
-
避免悬空指针:智能指针通常会在内部使用nullptr来避免悬空指针的问题,即确保被释放的内存块的指针在被释放后被置为空指针。
常见的智能指针包括std::unique_ptr、std::shared_ptr和std::weak_ptr。其中,std::unique_ptr用于独占拥有一个动态分配的对象,std::shared_ptr用于多个指针共享拥有一个对象,而std::weak_ptr则用于协助std::shared_ptr进行循环引用的解决。
🥙 总结一下智能指针的原理:
- RAII特性
- 重载operator*和opertaor->,具有像指针一样的行为。
👉🏻C++标准库提供的常见智能指针
C++中的智能指针是一种用于管理动态分配的内存的工具,它可以帮助开发人员避免内存泄漏和悬空指针等问题。C++标准库提供了三种主要的智能指针类型:std::unique_ptr
、std::shared_ptr
和std::weak_ptr
。
-
std::unique_ptr:
std::unique_ptr
代表独占所有权的指针,即同一时刻只能有一个std::unique_ptr
指向特定的资源(如堆上的对象)。- 当
std::unique_ptr
被销毁时,它所管理的资源也会被自动释放,从而避免了内存泄漏的风险。 std::unique_ptr
不支持拷贝构造和赋值操作,因此确保了资源的独占性。
-
std::shared_ptr:
std::shared_ptr
允许多个指针共享对同一资源的所有权,它使用引用计数来跟踪资源的引用次数。- 当最后一个指向资源的
std::shared_ptr
被销毁时,资源会被释放。 std::shared_ptr
的引用计数机制可以防止资源过早释放,但也可能导致循环引用的问题。
-
std::weak_ptr:
std::weak_ptr
是为了解决std::shared_ptr
可能出现的循环引用问题而引入的。- 它允许观察由
std::shared_ptr
管理的资源,但不拥有资源。因此,使用std::weak_ptr
可以打破std::shared_ptr
可能出现的循环引用,避免内存泄漏。
如上便是本期的所有内容了,如果喜欢并觉得有帮助的话,希望可以博个点赞+收藏+关注🌹🌹🌹❤️ 🧡 💛,学海无涯苦作舟,愿与君一起共勉成长