C++——8(智能指针&STL)
一、智能指针
头文件:
智能指针:
智能指针(smart pointer)是个特殊的类模板,重载了->
和*
运算符,实现了C++的自动内存回收机制。
分类:
auto_ptr:C++11中已经弃用,有设计缺陷不足之处
shared_ptr:
共享智能指针,允许多个智能指针共享同一资源,通过引用计数自动管理内存。(当引用该指针的数目为0时,自动释放)
- 核心原理:
每个
shared_ptr
维护一个 “引用计数”,记录有多少个shared_ptr
指向同一资源。当新的
shared_ptr
指向资源时,计数 + 1;当shared_ptr
销毁或重新赋值时,计数 - 1。当计数为
0
时,自动释放资源。/*=============================================== * 文件名称:2_SharedPoint.cpp * 创 建 者:青木莲华 * 创建日期:2025年09月04日 * 描 述:智能指针_Shared 示例 ================================================*/ #include <iostream> using namespace std; #include <memory> #include <unistd.h> class Demo { public: Demo(){ cout << __func__ << endl; } ~Demo(){ cout << __func__ << endl; } void func() { cout << "Demo::func()" << endl; } }; void test() { //定义共享智能指针 不安全写法 //shared_ptr<Demo> p(new Demo()); //安全写法 安全创建堆区空间 shared_ptr<Demo> p = make_shared<Demo>(); //计数值 = 1 shared_ptr<Demo> p2 = p; //计数值 = 2 p->func(); p.reset(); //结束生命周期(智能指针),引用计数值 = 1 sleep(3); //sleep延时,查看是否释放资源 p2->func(); //执行完后,函数结束,引用计数值 == 0 ,自动回收资源 } int main(int argc, char *argv[]) { test(); return 0; }
运行截图
unique_ptr:
独占资源智能指针,资源只能被一个unique_ptr
持有(独占所有权),转移所有权后原指针失效。
- 核心特点:
不可拷贝,只能移动:通过
std::move
转移所有权,原指针变为nullptr
。高效轻量:无引用计数开销,性能接近原始指针。
支持自定义删除器:可管理非内存资源(如文件句柄、网络连接)。
兼容 STL 容器:因支持移动语义,可安全存入
vector
等容器。#include <iostream> using namespace std; #include <memory> class Demo { public: Demo(){ cout << __func__ << endl; } ~Demo(){ cout << __func__ << endl; } void func() { cout << "Demo::func()" << endl; } }; unique_ptr<Demo> test() { //资源独占智能指针 unique_ptr<Demo> p = make_unique<Demo>(); p->func(); //unique_ptr<Demo> p2(p); 不能直接初始化,因为独占 //移交所有权 p ---> p2 , p = nullptr; unique_ptr<Demo> p2 = move(p); p2->func(); //return p2; (隐式)函数返回unique指针时,会自动移交所有权 return move(p2); //显示返回移交 } int main(int argc, char *argv[]) { unique_ptr<Demo> p = test(); //接收返回指针,并接收所有权 cout << "-----------" << endl; p->func(); return 0; }
运行结果
weak_ptr:
配合shared_ptr
使用,不增加引用计数,用于解决shared_ptr
的循环引用问题。
- 核心特点:
不管理资源生命周期,仅 “观察”
shared_ptr
管理的资源。通过
lock()
方法获取shared_ptr
(若资源未释放),或用expired()
检查资源是否有效。/*=============================================== * 文件名称:4_WeakPoint.cpp * 创 建 者:青木莲华 * 创建日期:2025年09月04日 * 描 述:智能指针_Weak 示例 ================================================*/ #include <iostream> using namespace std; #include <memory> #include <unistd.h> class Demo { public: Demo(){ cout << __func__ << endl; } ~Demo(){ cout << __func__ << endl; } void func() { cout << "Demo::func()" << endl; } }; void test() { shared_ptr<Demo> p = make_shared<Demo>(); weak_ptr<Demo> wp = p; //协助管理shared_ptr p->func(); if(wp.expired()) //判断堆区中对象是否释放 { cout << "Obj is not exist" << endl; } else { cout << "Obj exist" << endl; } p.reset(); //结束shared_ptr生命周期 if(wp.expired()) //判断堆区中对象是否释放 { cout << "Obj is not exist" << endl; } else { cout << "Obj exist" << endl; } } int main(int argc, char *argv[]) { test(); return 0; }
运行结果
智能指针 所有权 线程安全 适用场景 核心缺陷 auto_ptr
独占(旧版) 否 简单场景(已弃用) 所有权转移易出错、功能弱 shared_ptr
共享 引用计数线程安全 多指针共享资源 循环引用导致内存泄漏 unique_ptr
独占 否 单指针管理资源、STL 容器 不可共享 weak_ptr
弱引用(无) 否 解决 shared_ptr 循环引用 不能直接访问资源
二、标准模板库 (STL)
STL:
主要是一些容器
的集合,list、vector、set、map等。
目的:
标准化组件,可以使用现成的组件。
分类:
容器
:实现了数组、链表、队列、等等,实质是模板类迭代器
:一种复杂的指针,可以通过其读写容器中的对象,实质是运算符重载- 空间配置器:容器的空间配置管理的模板类
- 配接器:用来修饰容器、仿函数、迭代器接口
算法
:算法通过迭代器对容器实现相关操作- 仿函数:类似函数,通过重载()运算符来模拟函数行为的类
组件间关系:
container(容器)
通过allocator(配置器)
取得数据储存空间,algorithm(算法)
通过iterator(迭代器)
存取container(容器)
内容,functor(仿函数)
可以协助algorithm(算法)
完成不同的策略变化,adapter(配接器)
可以修饰或套接functor(仿函数)
。
三、容器(Container)
序列容器
Vector:
动态数组容器
Deque:
双端队列容器
list:
双向链表容器关联容器
Set / multiset:
根据元素值自动排序,由红黑树实现,便于查找(set内相同元素只能出现一次,multiset可以存在多次)map / multimap:
成对的键值 / 实值,由红黑树实现(map 内相同元素只能出现一次,multimap可以出现多次)Hash相关:
hash_map、hash_set、hash_multimap、hash_multiset等
1.List 集合
概述:
<list>
是一个非常重要的容器类,用于存储元素集合,支持双向迭代器。<list>
是 C++ 标准模板库(STL)中的一个序列容器,它允许在容器的任意位置快速插入和删除元素。不需要在创建时指定大小,并且可以在任何位置添加或删除元素,而不需要重新分配内存。以下是
<list>
容器的一些基本操作:
- 包含头文件:
#include <list>
- 声明列表:
std::list<T> mylist;
,其中T
是存储在列表中的元素类型。- 插入元素:
mylist.push_back(value);
- 删除元素:
mylist.pop_back();
或mylist.erase(iterator);
- 访问元素:
mylist.front();
和mylist.back();
- 遍历列表:使用迭代器
for (auto it = mylist.begin(); it != mylist.end(); ++it)
特点
- 双向迭代:
<list>
提供了双向迭代器,可以向前和向后遍历元素。- 动态大小:与数组不同,
<list>
的大小可以动态变化,不需要预先分配固定大小的内存。- 快速插入和删除:可以在列表的任何位置快速插入或删除元素,而不需要像向量那样移动大量元素。
示例代码:
/*=============================================== * 文件名称:List.cpp * 创 建 者:青木莲华 * 创建日期:2025年09月04日 * 描 述:集合示例 ================================================*/ #include <iostream> using namespace std; #include <list> class Good { public: Good(){} Good(string name , string note , double price): g_name(name) , g_note(note) , g_price(price) {} friend ostream& operator<<(ostream& out,const Good &g) { out << "商品名:" << g.g_name << endl; out << "商品简介:" << g.g_note << endl; out << "商品价格:" << g.g_price << endl; return out; } private: string g_name; string g_note; double g_price; }; int main(int argc, char *argv[]) { Good good_a("小牛","牛牛的小牛车",20000); Good good_b("大牛","牛牛的大牛兰博基尼",9999999); Good good_c("二牛","牛牛的二手车",1000); list<Good> goods; goods.push_back(good_a); goods.push_back(good_b); goods.push_back(good_c); for(Good good : goods) { cout << good << endl; cout << "=======================" << endl; } return 0; }
运行截图
2.Vector 动态数组
概述:
C++ 中的 vector 是一种序列容器,它允许你在运行时动态地插入和删除元素。vector 是基于数组的数据结构,但它可以自动管理内存,这意味着你不需要手动分配和释放内存。- 基本特性:
- 动态大小:
vector
的大小可以根据需要自动增长和缩小。- 连续存储:
vector
中的元素在内存中是连续存储的,这使得访问元素非常快速。- 可迭代:
vector
可以被迭代,你可以使用循环(如for
循环)来访问它的元素。- 元素类型:
vector
可以存储任何类型的元素,包括内置类型、对象、指针等。
vector示例:
/*=============================================== * 文件名称:Vector.cpp * 创 建 者:青木莲华 * 创建日期:2025年09月04日 * 描 述:Vector容器 ================================================*/ #include <iostream> using namespace std; #include <vector> class Student { public: //无参 Student(){} //有参 Student(string sno,string sname,int age,bool gender) :sno(sno),sname(sname),sage(age),gender(gender){}; //重构输出 friend ostream& operator<<(ostream &out,const Student *stu) { out << "学号:" << stu->sno << endl; out << "姓名:" << stu->sname << endl; out << "年龄:" << stu->sage << endl; string gen = (stu->gender ? "男" : "女"); out << "性别:" << gen << endl; return out; } private: string sno; string sname; int sage; bool gender; }; int main(int argc, char *argv[]) { //1.创建Student Vector 默认为空 vector<Student *> students; //2.添加元素 尾部插入 students.push_back(new Student("25060101", "张三",18,true)); students.push_back(new Student("25060102", "李四",20,true)); students.push_back(new Student("25060103", "王五",19,false)); //打印vector元素个数 cout << "vector_size = " << students.size() << endl; cout << "=====================" << endl; //迭代打印 + 回收资源 for(Student *stu : students) { cout << stu << endl; delete stu; } students.clear(); cout << "=====================" << endl; cout << "vector_size = " << students.size() << endl; return 0; }
运行截图
3.Deque 双端队列
概述:
在 C++中,
<deque>
是标准模板库(STL)的一部分,它提供了双端队列(double-ended queue)的实现。双端队列是一种允许在两端进行插入和删除操作的线性数据结构。
常用操作:
函数名称 功能描述 deque()
默认构造函数,创建一个空的 deque
容器。deque(size_type n)
创建一个包含 n
个默认值元素的deque
容器。push_back(const T& value)
在容器末尾添加 value
元素。pop_back()
移除容器末尾的元素。 push_front(const T& value)
在容器前端添加 value
元素。pop_front()
移除容器前端的元素。 insert(iterator pos, const T& value)
在 pos
位置插入value
元素。erase(iterator pos)
移除 pos
位置的元素。size()
返回容器中的元素个数。 clear()
清除容器中的所有元素。 at(size_type pos)
返回 pos
位置的元素,并进行范围检查。front()
返回第一个元素的引用。 back()
返回最后一个元素的引用。 begin()
返回指向第一个元素的迭代器。 end()
返回指向末尾元素后一位置的迭代器。
dequeue示例:
/*=============================================== * 文件名称:Deque.cpp * 创 建 者:青木莲华 * 创建日期:2025年09月04日 * 描 述:双端队列示例 ================================================*/ #include <iostream> using namespace std; #include <deque> class Good { public: Good(){} Good(string name , string note , double price): g_name(name) , g_note(note) , g_price(price) {} friend ostream& operator<<(ostream& out,const Good &g) { out << "商品名:" << g.g_name << endl; out << "商品简介:" << g.g_note << endl; out << "商品价格:" << g.g_price << endl; return out; } private: string g_name; string g_note; double g_price; }; int main(int argc, char *argv[]) { deque<Good> goods; Good good_a("小牛","牛牛的小牛车",20000); Good good_b("大牛","牛牛的大牛兰博基尼",9999999); Good good_c("二牛","牛牛的二手车",1000); goods.push_back(good_a); goods.push_back(good_b); goods.push_back(good_c); for(Good good : goods) { cout << good << endl; cout << "=======================" << endl; } return 0; }
运行截图