智能指针 smart pointer
在你创建一个指针空间时,程序中发生任何异常时我们都需要去释放这个自定义空间,但我们一般的释放内存的程序在最后面,万一程序中途中断就释放不了
(^U^)ノ~YO
作用:
用来防止内存泄漏,用来在创建这个智能指针后,通过智能指针去使用这块内存,而不需要关心的释放,释放时由系统自动释放
每多个指针指向内存,则引用计数器+1
shared_ptr
共享资源所有权的指针,多个共享的智能指针指向同一块内存
/*===============================================
* 文件名称:share_ptr.cpp
* 创 建 者: memories
* 创建日期:2023年06月06日
* 描 述:have a nice day
================================================*/
#include <iostream>
#include <memory>
using namespace std;
class Demo
{
public:
Demo(int size):len(size),p(nullptr)
{
if(len > 0)
{
cout << "Demo::Demo(),len=" << len << endl;
p = new int[len];
}
}
virtual ~Demo()
{
if(p != nullptr)
{
delete []p;
p = nullptr;
cout << "delete success" << endl;
}
}
void show()
{
cout << "Demo::show()" << endl;
}
private:
int len;
int *p;
};
void debug()
{
cout << "---------------" << endl;
}
void func()
{
///模板类
shared_ptr<Demo> p = make_shared <Demo>(100);//定义了一个名为p的共享指针,其大小为Demo的大小,要使用Demo类的数据类型。。。。p指向由make_shared创建的Demo类的空间
debug();
// shared_ptr<Demo> p ( new Demo(100));
// p->show();
// 获得demo的对象
(*p).show();
debug();
//获得demo对象的指针
Demo *pDemo = p.get();//这个.操作的是shared_ptr类里的,相当于p是shared_ptr中的对象,获得指向Demo类的指针;
pDemo->show();
debug();
用p2也指向Demo/
shared_ptr<Demo> p2 = p;
p2->show();
debug();
//查找指向Demo类的指针个数/
cout << "reference cout = " << p.use_count() << endl;
cout << "reference cout = " << p2.use_count() << endl;
///让p2放弃指向Demo/
p2.reset();
if(p2 == nullptr)
{
cout << "p2 is a null ptr" << endl;
}
else
cout << "p2 is still alive" << endl;
cout << "reference cout = " << p.use_count() << endl;
cout << "reference cout = " << p2.use_count() << endl;
}
int main()
{
func();
return 0;
}
//
shared_ptr<Demo> p = make_shared <Demo>(100);
这行代码使用了 C++11 中的智能指针 `shared_ptr`,并创建了一个名为 `p` 的指向 `Demo` 类型对象的智能指针。
`make_shared` 是一个模板函数,用于在动态内存中创建一个对象并返回一个指向该对象的 `shared_ptr` 智能指针。在这里,`make_shared` 接受一个 `Demo` 类型的参数 `100`,用于初始化 `Demo` 类型对象的成员变量。
因此,这行代码的作用是创建一个 `Demo` 类型对象,并将其封装在一个 `shared_ptr` 智能指针中,然后将该智能指针赋值给 `p` 变量。这样做的好处是,`shared_ptr` 会自动管理对象的生命周期,当没有任何智能指针指向该对象时,`shared_ptr` 会自动释放该对象的内存空间,避免了内存泄漏的问题。
unique_ptr
独占资源所有权的指针,一块内存只能被一个指针独占所有权,但是所有权可以转移
/*===============================================
* 文件名称:unique_ptr.cpp
* 创 建 者: memories
* 创建日期:2023年06月06日
* 描 述:have a nice day
================================================*/
#include <iostream>
#include <memory>
using namespace std;
class Demo
{
public:
Demo(int size):len(size),p(nullptr)
{
if(len > 0)
{
cout << "Demo::Demo(),len=" << len << endl;
p = new int[len];
}
}
virtual ~Demo()
{
if(p != nullptr)
{
delete []p;
p = nullptr;
cout << "delete success" << endl;
}
}
void show()
{
cout << "Demo::show()" << endl;
}
private:
int len;
int *p;
};
void debug()
{
cout << "---------------" << endl;
}
void func()
{
///模板类
unique_ptr<Demo> p = make_unique <Demo>(100);//定义了一个名为p的独占指针,其大小为Demo的大小,要使用Demo类的数据类型。。。。p指向由make_unique创建的Demo类的空间
debug();
p->show();
debug();
// 获得demo的对象
(*p).show();
debug();
//获得demo对象的指针
Demo *pDemo = p.get();//这个.操作的是shared_ptr类里的,相当于p是shared_ptr中的对象,获得指向Demo类的指针;
pDemo->show();
debug();
//不允许独占的智能指针指向同一块内存
// unique_ptr<Demo> p2 = p; 是错误的
unique_ptr<Demo> p2 = move(p);//将独占的智能指针转移
p2->show();
(*p2).show();
if(p != nullptr )
{
cout << "p is still alive" << endl;
}
else
cout << "p is a null ptr" << endl;
debug();
pDemo = p2.get();//把pDemo的所有权从p转移到p2
pDemo->show();
debug();
}
int main()
{
func();
return 0;
}
weak_ptr
共享资源的观察者,需要和std::shared_ptr 一起使用ヽ( ̄ω ̄( ̄ω ̄〃)ゝ
不影响资源的生命周期,共享指针赋值的时候引用的计数器会+1,它是强引用,使用weak_ptr不引发引用计数器的增加,是一个共有资源的观察者,
/*===============================================
* 文件名称:weak_ptr.cpp
* 创 建 者: memories
* 创建日期:2023年06月06日
* 描 述:have a nice day
================================================*/
#include <iostream>
#include <memory>
using namespace std;
class B;
class A
{
public:
A()
{
cout << "A::A()" << endl;
}
virtual ~A()
{
cout << "A::~A()" << endl;
}
void show()
{
cout << "A::show()" << endl;
}
//shared_ptr<B> pointer;
weak_ptr<B> pointer;
};
class B
{
public:
B()
{
cout << "B::B()" << endl;
}
virtual ~B()
{
cout << "B::~B()" << endl;
}
void show()
{
cout << "B::show()" << endl;
}
//shared_ptr<A> pointer;
weak_ptr<A> pointer;
};
void debug()
{
cout << "---------------" << endl;
}
void func()
{
shared_ptr<A> sp_a = make_shared<A>();
shared_ptr<B> sp_b = make_shared<B>();
debug();
cout << "reference count of sp_a is " << sp_a.use_count() << endl;
cout << "reference count of sp_b is " << sp_b.use_count() << endl;
sp_a->show();
sp_b->show();
debug();
sp_a->pointer = sp_b;//和std::shared_ptr 一起使用
sp_b->pointer = sp_a;
cout << "reference count of sp_a is " << sp_a.use_count() << endl;
cout << "reference count of sp_b is " << sp_b.use_count() << endl;
sp_a->show();
sp_b->show();
debug();
}
int main()
{
func();
return 0;
}
STL标准模板库
1 容器(Container),是一种数据结构,如list,vector,和deque ,以模板类的方法提供。为了访问容器中的数据,可以使用由容器类输出的迭代器
2 迭代器(Iterator),提供了访问容器中对象的方法。例如,可以使用一对迭代器指定list或vector中的一定范围的对象。迭代器就如同一个指针。
3 算法(Algorithm),是用来操作容器中的数据的模板函数。
例如,STL用sort()来对一个vector中的数据进行排序,用find()来搜索一个list中的对象,函数本身与他们操作的数据的结构和类型无关,
因此他们可以在从简单数组到高度复杂容器的任何数据结构上使用;
4 仿函数(Functor)仿函数(functor),就是使一个类的使用看上去象一个函数。其实现就是类中实现一个operator(),这个类就有了类似函数的行为,就是一个仿函数类了
5 适配器(Adaptor)适配器是使一种事物的行为类似于另外一种事物行为的一种机制”,适配器对容器进行包装,使其表现出另外一种行为。
例如,stack<int, vector<int> >实现了栈的功能,但其内部使用顺序容器vector<int>来存储数据。(相当于是vector<int>表现出了栈的行为)
6 分配器(allocator)用于分配管理内存空间。其实我们可以把allocator看成一个简易的内存池,其主要适用于在使用容器时,对内存空间的动态分配
vector 向量
将元素置于一个动态数组中加以管理,可以随机存取元素(用索引直接存取),数组尾部添加或移除元素非常快速。但是在中部或头部安插元素比较费时
/*===============================================
* 文件名称:vector.cpp
* 创 建 者: memories
* 创建日期:2023年06月06日
* 描 述:have a nice day
================================================*/
#include <iostream>
#include <vector>
using namespace std;
void debug()
{
cout << "-------------------------------------------------------" << endl;
}
void printVec(int id, vector<int>& vecInt)
{
cout << id << "==[";
for(int item:vecInt)
cout << item << ",";
cout << "]" << endl;
}
int main()
{
vector<int> vecInt;//vector是个模板类
cout << "capacity=" << vecInt.capacity() << endl;//capacity()容量由vector自行开辟
cout << "size=" << vecInt.size() << endl;//
for(int i=1;i<=10;i++)
{
vecInt.push_back(i);//push_back()压栈,数据第一个在最下部
}
cout << "capacity=" << vecInt.capacity() << endl;
cout << "size=" << vecInt.size() << endl;
for(int i=11;i<=200;i++)
{
vecInt.push_back(i);
}
cout << "capacity=" << vecInt.capacity() << endl;
cout << "size=" << vecInt.size() << endl;
cout << vecInt[100] << endl;
/遍历的方法1//
//通过下标操作符
for(int i=0;i<vecInt.size();i++)
{
cout << vecInt[i] << ",";
}
cout << endl;
/遍历的方法2//
//通过at()函数
for(int i=0;i<vecInt.size();i++)
{
cout << vecInt.at(i) << ",";
}
cout << endl;
/遍历的方法3//
//通过 int item:使用新的for方法
for( int item:vecInt )
{
cout << item << ",";
}
cout << endl;
4使用迭代器iterator
//
vector<int>::iterator iter;//定义一个迭代器,可以看作特殊的指针
vector<int>::reverse_iterator riter;
for(iter = vecInt.begin(); iter != vecInt.end();iter++)
{
cout << *iter << ",";
}
cout << endl;
debug();
///删除部分数据1
for(int i=0;i<100;i++)
{
vecInt.pop_back();
}
printVec(1,vecInt);
/反向迭代器遍历数据2///
for(auto iter = vecInt.rbegin();iter != vecInt.rend();iter++)
{
cout << *iter << ",";
}
cout << endl;
///删除所有数据2
vecInt.clear();
if (vecInt.empty() == true)
cout << "now there is no data" << endl;
debug();
/不同的构造函数//
vector<int> v2(100,1000);//构造时往容器里放置100个1000
printVec(2,v2);
debug();
vector<int> v3(v2);//拷贝构造
printVec(3,v3);
debug();
return 0;
}
deque
是“double-ended queue”的缩写,可以随机存取元素(用索引直接存取),数组头部和尾部添加或移除元素都非常快速。但是在中部安插元素比较费时
list 双向链表
双向链表,不提供随机存取(按顺序走到需存取的元素),在任何位置上执行插入或删除动作都非常迅速,内部只需调整一下指针
/*===============================================
* 文件名称:list.cpp
* 创 建 者: memories
* 创建日期:2023年06月06日
* 描 述:have a nice day
================================================*/
#include <iostream>
#include <list>
using namespace std;
void printList(int id,list<int>& list)
{
cout << id << "=[" ;
for(int item:list)
{
cout << item << ",";
}
cout << "]" << endl;
}
void debug()
{
cout << "--------------------------------------------------------" << endl;
}
int main()
{
list<int> liInt(10,100);
printList(1,liInt);
list<int> li;
for(int i=0;i<100;i++)
{
if(i%2 == 0)
{
li.push_front(i);
}
else
li.push_back(i);
}
printList(2,li);
debug();
//使用迭代器遍历//
for(auto iter = li.begin();iter != li.end();iter++)
{
cout << *iter << ",";
}
cout << endl;
debug();
//使用反向迭代器遍历//
for(auto iter = li.rbegin();iter != li.rend();iter++)
{
cout << *iter << ",";
}
cout << endl;
debug();
///删除数据元素
for(int i=0;i<40;i++)
{
if(i%2 == 0)
li.pop_front();
else
li.pop_back();
}
printList(3,li);
debug();
///删除全部数据
li.clear();
cout << "size of li = " << li.size() << endl;
if(li.empty() == true)
{
cout << "now li is empty" << endl;
}
return 0;
}
关联式容器(Associated containers) map
Set/Multiset
内部的元素依据其值自动排序,Set内的相同数值的元素只能出现一次,Multisets内可包含多个数值相同的元素,内部由二叉树实现,便于查找
Map/Multimap
Map的元素是成对的键值/实值,内部的元素依据其值自动排序,Map内的相同数值的元素只能出现一次,Multimaps内可包含多个数值相同的元素,内部由二叉树实现,便于查找
/*===============================================
* 文件名称:map.cpp
* 创 建 者: memories
* 创建日期:2023年06月06日
* 描 述:have a nice day
================================================*/
#include <iostream>
#include <map>
#include <string>
using namespace std;
void debug()
{
cout << "-----------------------------------------------" << endl;
}
void printMap(int id,map<int,string>& map)
{
cout << id << ":" << endl;
for(auto item: map)
{
cout << item.first << "->" << item.second << endl;
}
cout << endl;
}
int main()
{
map<int,string> smap = {{1,"zhangsan"}, {2,"lisi"},{3,"wangwu"}};//三对键值
printMap(1,smap);
新增数据
smap[4] = "jackson";
printMap(2,smap);
覆盖数据
smap[4] = "jocker";
printMap(3,smap);
/迭代器//
// map<int,string>::iterator iter;
for(auto iter = smap.begin();iter != smap.end();iter++)
{
cout << iter->first << "->" << iter->second << endl;
}
cout << endl;
for(auto iter = smap.rbegin();iter != smap.rend();iter++)
{
cout << iter->first << "->" << iter->second << endl;
}
cout << endl;
/通过某一键值找到其值/
auto iter = smap.find(3);
cout << iter->first << "->" << iter->second << endl;
auto itere = smap.find(4);
if(itere != smap.end())
{
cout << itere->first << "->" << itere->second << endl;
}
else
{
cout << "didn't find value for 4" << endl;
}
/删除数据//
smap.erase(itere);
printMap(5,smap);
/全部删除//
smap.clear();
printMap(6,smap);
return 0;
}