c++:智能指针

文章目录

  • 前言
  • 一、内存泄漏
    • 1.1 内存泄漏的定义
    • 1.2 内存泄漏的常见原因
    • 1.3内存泄漏的危害
  • 二、智能指针的用法和模拟实现
    • 2.1 RAII
      • 2.1.1 RAII的工作原理
      • 2.1.2 RAII的优点
    • 2.2 智能指针的原理和设计思路
    • 2.3 智能指针的种类和特点
      • 2.3.1 std::auto_ptr
      • 2.3.2 std::unique_ptr
      • 2.3.3 std::shared_ptr
      • 2.3.4 std::weak_ptr
  • 三. 智能指针使用时注意事项
  • 总结


前言

智能指针(smart pointer)是一种用来防止内存泄漏的编程技术,它利用对象管理资源的方式(又名RAII——Resource Acquisition Is Initialization),即利用对象析构函数在生命周期结束时自行调用的特性,让编译器自行释放动态开辟的空间。


一、内存泄漏

1.1 内存泄漏的定义

内存泄漏通常发生在使用了new或malloc等函数动态分配内存后,忘记了对应的delete或free调用,或者是因为逻辑错误导致这些调用未能执行。这种情况下,程序占用的内存会逐渐增加,最终可能导致系统资源耗尽,程序崩溃或运行缓慢。

1.2 内存泄漏的常见原因

1.忘记释放内存:程序员在堆上动态分配内存后,忘记或未能正确地释放它。
2.异常处理不当:当程序发生异常时,执行流程可能会发生改变,导致某些正常流程中的内存释放操作无法执行


void MemoryLeaks()
{
   
	// 1.内存申请了忘记释放
	int* p1 = (int*)malloc(sizeof(int));
	int* p2 = new int;
 
	// 2.异常安全问题
	int* p3 = new int[10];
	Func(); // 这里Func函数如果抛异常就会导致 delete[] p3未执行,p3没被释放.
	delete[]p3;
}

3.拷贝构造函数和赋值运算符未正确处理动态内存:当类对象包含动态分配的内存时,拷贝构造函数和赋值运算符需要特别处理,以确保在对象复制或赋值时不会导致内存泄漏。
4.容器使用不当:C++标准库提供了许多容器类(如std::vector、std::string等),它们内部自动管理内存。然而,如果在使用这些容器时不当(如将一个容器作为另一个容器的元素,并在某个时刻改变了容器的容量),也可能导致内存泄漏。

5.循环引用:两个或多个对象相互引用,形成一个循环,导致内存无法被释放。(往下会介绍此种泄露的原因和解决办法)

1.3内存泄漏的危害

内存泄漏会导致程序占用的内存逐渐增加,最终可能导致系统资源耗尽,程序崩溃或运行缓慢。此外,内存泄漏还可能引发其他严重问题,如内存碎片、系统不稳定等
智能指针的出现就是解决这种危害的一种方法。

二、智能指针的用法和模拟实现

2.1 RAII

实际上RAII就是利用一个类来进行动态开辟的资源的管理,这个类是一个模板类,我们只需要在实例化这个类的时候传需要被管理的资源的类型,如此就可以很好的解决内存泄漏问题
RAII(Resource Acquisition Is Initialization)是一种管理资源的技术,它利用C++对象的生命周期来自动管理资源。RAII的核心思想是,将资源的获取(如动态内存分配、文件打开、互斥锁锁定等)与对象的构造绑定在一起,而将资源的释放(如内存释放、文件关闭、互斥锁解锁等)与对象的析构绑定在一起。这样,当对象超出其作用域或被显式销毁时,资源会自动被释放

2.1.1 RAII的工作原理

1.资源获取与对象构造:
当一个对象被构造时,它会自动获取所需的资源。这通常是通过调用构造函数中的代码来实现的。
构造函数负责确保资源被正确分配和初始化。

2.资源使用与对象生存:
在对象的生命周期内,资源可以被安全地使用。
对象的成员函数可以访问和操作这些资源。

3.资源释放与对象析构:
当对象被销毁时(例如,超出其作用域、被显式删除或作为另一个对象的成员而被销毁),它的析构函数会被自动调用。
析构函数负责释放资源,确保不会发生内存泄漏或其他资源泄漏。

2.1.2 RAII的优点

1.自动管理资源:RAII通过对象的生命周期来自动管理资源,减少了手动管理资源的复杂性和出错的可能性。
2.异常安全性:由于资源的释放是在析构函数中进行的,而析构函数在异常传播过程中总是会被调用,因此RAII提供了异常安全性。即使程序在资源使用期间抛出异常,资源也会被正确释放。

3.简化代码:使用RAII可以简化资源管理代码,使代码更加清晰和易于维护

2.2 智能指针的原理和设计思路

智能指针是一种能够自动管理指针指向内存的类模板。内部使用(RAII的原理)来自动释放内存。

智能指针中会重载operator*和opertaor->,具有像指针一样的行为

2.3 智能指针的种类和特点

智能指针主要分为两类:不带引用计数的智能指针和带引用计数的智能指针。d都包含在c++的标准库中的 memory 下面。

不带引用计数的智能指针:
auto_ptr :C++98标准库提供的智能指针,但由于其管理权会转移的特性,容易导致程序崩溃,因此不推荐使用。
scoped_ptr :C++11标准库提供的智能指针,防止拷贝,确保资源在同一作用域内被管理,离开作用域时自动释放资源。但C++17中已被弃用。
unique_ptr:C++11标准库提供的智能指针,不允许拷贝,但允许移动,确保资源的唯一所有权,离开作用域时自动释放资源。

带引用计数的智能指针:
shared_ptr :多个智能指针可以管理同一个资源,每个资源匹配一个引用计数。当智能指针指向该资源时,引用计数加1;当该指针不再使用该资源时,引用计数减1。当引用计数为0时,释放资源。shared_ptr是线程安全的,可直接用于多线程环境。但需要注意循环引用的问题。
weak_ptr :为了解决shared_ptr的循环引用问题而设计的。weak_ptr指向已被shared_ptr管理的资源时,不会增加其引用计数。在weak_ptr解除指向资源时,也不会减少引用计数。因此,weak_ptr不能单独管理资源,必须与shared_ptr配合使用。

2.3.1 std::auto_ptr

auto_ptr是在C++98版本中就给出的,它的实现原理是:管理权转移,只有一个对象能够管理资源(意味着转移后的那个指针会被悬空)
我们先来看看其模拟代码实现以及使用

template

你可能感兴趣的:(c++,开发语言)