【C++ 语言】智能指针 引入 ( 内存泄漏 | 智能指针简介 | 简单示例 )

简介: 【C++ 语言】智能指针 引入 ( 内存泄漏 | 智能指针简介 | 简单示例 )

文章目录

I . 智能指针 引入

II . 智能指针 简介

III . 智能指针 简单示例



I . 智能指针 引入


1 . 示例前提 : 定义一个 Student 类 , 之后将该类对象作为智能指针指向的对象 ;


class Student {
public:
  //构造函数
  Student()
  {
  cout << "Student 对象创建" << endl;
  }
  //析构函数
  ~Student()
  {
  cout << "Student 对象释放" << endl;
  }
};


2 . 栈内存创建对象 : 如果在栈内存中创建对象 , 在方法结束后 , 会自动释放 Student 对象 ;


//栈内存中创建对象 , 在方法结束后 , 会自动释放 Student 对象
void createInStack() {
  Student student;
}



3 . 堆内存创建对象 : 使用 new 在堆内存中创建对象时 , 在 该对象的 作用域 结束后 , 不会自动释放 Student 对象 ;



① 错误示例 : 如下方法中 , 只创建了对象 , 在作用域结束时 , 没有释放该对象 , 这样造成了内存泄漏 ;


//堆内存中创建对象 , 在方法结束后 , 不会自动释放 Student 对象
void createInHeap() {
  Student *student = new Student;
}


② 正确示例 : 使用 new 关键字在堆内存中创建了对象 , 必须在作用域结束前, 将该对象使用 delete 方法释放掉 , 否则会造成内存泄漏 ;


//堆内存中创建对象 , 在方法结束后 , 手动调用 delete 释放 Student 对象
void createInHeapAndDelete() {
  //在堆内存中创建对象
  Student* student = new Student;
  //手动释放 堆内存中创建的对象
  delete(student);



4 . 堆内存创建对象 使用智能指针指向该对象 : 堆内存中创建对象 , 将对象指针设置成智能指针 , 该对象在方法结束时会自动释放 ;


//堆内存中创建对象 , 将对象指针设置成智能指针 , 该对象在方法结束时会自动释放
void createInHeapWithSmartPointer() {
  Student* student = new Student;
  shared_ptr<Student> shared_student(student);
}



II . 智能指针 简介


C ++ 的 STL ( Standard Template Library 标准模板库 ) 提供了 四种智能指针 :



① shared_ptr : 指向的对象所有权 共享 , 多个指针指向同一个对象 ; 当最后一个智能指针销毁时 , 对象销毁 ;


② weak_ptr : 为了弥补 shared_ptr 的缺陷而引入的智能指针 ;


③ unique_ptr : 指向的对象所有权 互斥 , 同一时间 , 一个 对象 只能有一个 unique_ptr 智能指针 指向它 ;


④ auto_ptr ( 已弃用 ) : 该智能指针在 C++ 11 标准中 已弃用 , 但是为了向低版本兼容 , 目前仍可以使用 ;



写新代码就不要使用 auto_ptr 类型的智能指针了 , 推荐使用 unique_ptr 智能指针 , 该指针是 auto_ptr 的安全进阶版本 ;




III . 智能指针 简单示例


1 . 示例项目下载地址 :


主要代码及逻辑都在下面的主代码示例中 , 没有下载的必要 ;



2 . 头文件 :


// 007_SmartPointer.h: 标准系统包含文件的包含文件
// 或项目特定的包含文件。
#pragma once
#include <iostream>
// TODO: 在此处引用程序需要的其他标头。




3 . 主代码示例 :


// 007_SmartPointer.cpp: 定义应用程序的入口点。
//
#include "007_SmartPointer.h"
using namespace std;
//智能指针原理 :
//  智能指针本质 : 智能指针也是一个对象
//  智能指针存放 : 该智能指针对象处于 栈内存中 
//  智能指针释放 : 函数执行完毕后 , 就会调用智能指针对象的析构方法
//  判定引用计数 : 在智能指针对象析构方法的内部就会判定智能指针 操作对象 的引用计数
//  如果这个 操作对象的 引用计数为 0 ,  就会调用 delete 方法释放 操作对象 ; 
class Student {
public:
  //构造函数
  Student()
  {
  cout << "Student 对象创建" << endl;
  }
  //析构函数
  ~Student()
  {
  cout << "Student 对象释放" << endl;
  }
};
//栈内存中创建对象 , 在方法结束后 , 会自动释放 Student 对象
void createInStack() {
  Student student;
}
//堆内存中创建对象 , 在方法结束后 , 不会自动释放 Student 对象
void createInHeap() {
  Student *student = new Student;
}
//堆内存中创建对象 , 在方法结束后 , 手动调用 delete 释放 Student 对象
void createInHeapAndDelete() {
  //在堆内存中创建对象
  Student* student = new Student;
  //手动释放 堆内存中创建的对象
  delete(student);
}
//堆内存中创建对象 , 将对象指针设置成智能指针 , 该对象在方法结束时会自动释放
void createInHeapWithSmartPointer() {
  Student* student = new Student;
  shared_ptr<Student> shared_student(student);
}
//堆内存中创建对象 , 将对象指针设置成智能指针 , 该对象在方法结束时会自动释放
void createInHeapWithTwoSmartPointer() {
  Student* student = new Student;
  //声明了一个智能指针对象 , student 的引用计数变成 1
  shared_ptr<Student> shared_student1(student);
  //又声明了第二个智能指针对象 , student 的引用计数 变成 2
  shared_ptr<Student> shared_student2(student);
  //上面的两个智能指针对象处于栈中 , 当函数结束时 , 这两个智能指针本身会被释放掉
  //  释放两个智能指针后 , student 对象的引用计数又变成了 0 
  //  两个智能指针会被回收 , 回收智能指针时 , 会做判定 , 当 对象的引用计数为 0 时
  //  自动调用该对象的析构函数 , 释放该对象
}
int main()
{
  //C++ 11 STL 提供了两种类型的 智能指针
  //在方法中 , 有两种创建对象的方式 : ① 直接声明对象 , ② 使用 new 创建对象 ;  
  //  直接声明对象 , 是在栈内存中创建实例 , 方法结束后 , 该实例自动释放 ; 
  //  如果使用 new 创建对象 , 是在堆内存中创建 , 创建后返回一个对象的指针 ; 
  //  堆内存中的对象需要手动释放 , new 申请的对象 , 需要调用 delete 释放 ( delete 会触发虚构函数 ) ; 
  //  如果忘记手动释放使用 new 创建的对象 , 就会导致内存泄漏
  //  因此引入智能指针 , 可以防止忘记手动释放对象导致内存泄漏
  //栈内存中创建对象 , 自动释放 Student 对象
  cout << "栈内存中 创建 Student 对象" << endl;
  createInStack();
  //堆内存中创建对象 , 不会自动释放 Student 对象
  cout << "\n堆内存中 创建 Student 对象 , 不主动释放该对象" << endl;
  createInHeap();
  cout << "\n堆内存中 创建 Student 对象 , 主动 调用 delete 方法 释放该对象" << endl;
  //堆内存中创建对象 , 函数结束前手动调用 delete 方法 , 释放该对象
  createInHeapAndDelete();
  cout << "\n堆内存中 创建 Student 对象 , 将其设置成智能指针" << endl;
  //堆内存中创建对象 , 将对象指针设置成智能指针 , 该对象在方法结束时会自动释放
  createInHeapWithSmartPointer();
  //智能指针分类 : 
  //  共享智能指针 : shared_ptr , 该智能指针内部实现了引用计数 , 多个共享智能指针指向同一个对象时
  //  有 N 个 共享 智能指针同一个对象 , 其引用计数为 N
  return 0;
}



运行结果 :


栈内存中 创建 Student 对象
Student 对象创建
Student 对象释放
堆内存中 创建 Student 对象 , 不主动释放该对象
Student 对象创建
堆内存中 创建 Student 对象 , 主动 调用 delete 方法 释放该对象
Student 对象创建
Student 对象释放
堆内存中 创建 Student 对象 , 将其设置成智能指针
Student 对象创建
Student 对象释放

image.png


目录
相关文章
|
5月前
|
缓存 安全 编译器
C++面试周刊(3):面试不慌,这样回答指针与引用,青铜秒变王者
《C++面试冲刺周刊》第三期聚焦指针与引用的区别,从青铜到王者级别面试回答解析,助你21天系统备战,直击高频考点,提升实战能力,轻松应对大厂C++面试。
522 132
C++面试周刊(3):面试不慌,这样回答指针与引用,青铜秒变王者
|
3月前
|
存储 安全 Java
【Golang】(4)Go里面的指针如何?函数与方法怎么不一样?带你了解Go不同于其他高级语言的语法
结构体可以存储一组不同类型的数据,是一种符合类型。Go抛弃了类与继承,同时也抛弃了构造方法,刻意弱化了面向对象的功能,Go并非是一个传统OOP的语言,但是Go依旧有着OOP的影子,通过结构体和方法也可以模拟出一个类。
259 1
|
10月前
|
存储 负载均衡 算法
基于 C++ 语言的迪杰斯特拉算法在局域网计算机管理中的应用剖析
在局域网计算机管理中,迪杰斯特拉算法用于优化网络路径、分配资源和定位故障节点,确保高效稳定的网络环境。该算法通过计算最短路径,提升数据传输速率与稳定性,实现负载均衡并快速排除故障。C++代码示例展示了其在网络模拟中的应用,为企业信息化建设提供有力支持。
298 15
|
5月前
|
存储 C++
C++语言中指针变量int和取值操作ptr详细说明。
总结起来,在 C++ 中正确理解和运用 int 类型地址及其相关取值、设定等操纵至关重要且基础性强:定义 int 类型 pointer 需加星号;初始化 pointer 需配合 & 取址;读写 pointer 执向之处需配合 * 解引用操纵进行。
523 12
|
6月前
|
安全 C语言 C++
比较C++的内存分配与管理方式new/delete与C语言中的malloc/realloc/calloc/free。
在实用性方面,C++的内存管理方式提供了面向对象的特性,它是处理构造和析构、需要类型安全和异常处理的首选方案。而C语言的内存管理函数适用于简单的内存分配,例如分配原始内存块或复杂性较低的数据结构,没有构造和析构的要求。当从C迁移到C++,或在C++中使用C代码时,了解两种内存管理方式的差异非常重要。
239 26
|
10月前
|
存储 算法 安全
企业员工数据泄露防范策略:基于 C++ 语言的布隆过滤器算法剖析[如何防止员工泄密]
企业运营过程中,防范员工泄密是信息安全领域的核心议题。员工泄密可能致使企业核心数据、商业机密等关键资产的流失,进而给企业造成严重损失。为应对这一挑战,借助恰当的数据结构与算法成为强化信息防护的有效路径。本文专注于 C++ 语言中的布隆过滤器算法,深入探究其在防范员工泄密场景中的应用。
235 8
|
C语言 C++
C++ 简介
C++ 简介
274 21
|
存储 程序员 C++
深入解析C++中的函数指针与`typedef`的妙用
本文深入解析了C++中的函数指针及其与`typedef`的结合使用。通过图示和代码示例,详细介绍了函数指针的基本概念、声明和使用方法,并展示了如何利用`typedef`简化复杂的函数指针声明,提升代码的可读性和可维护性。
|
存储 程序员 编译器
什么是内存泄漏?C++中如何检测和解决?
大家好,我是V哥。内存泄露是编程中的常见问题,可能导致程序崩溃。特别是在金三银四跳槽季,面试官常问此问题。本文将探讨内存泄露的定义、危害、检测方法及解决策略,帮助你掌握这一关键知识点。通过学习如何正确管理内存、使用智能指针和RAII原则,避免内存泄露,提升代码健壮性。同时,了解常见的内存泄露场景,如忘记释放内存、异常处理不当等,确保在面试中不被秒杀。最后,预祝大家新的一年工作顺利,涨薪多多!关注威哥爱编程,一起成为更好的程序员。
586 0
|
容器
在使用指针数组进行动态内存分配时,如何避免内存泄漏
在使用指针数组进行动态内存分配时,避免内存泄漏的关键在于确保每个分配的内存块都能被正确释放。具体做法包括:1. 分配后立即检查是否成功;2. 使用完成后及时释放内存;3. 避免重复释放同一内存地址;4. 尽量使用智能指针或容器类管理内存。