首页 / 资讯中心 / 文章详情

C++内存管理 + 模板

C++内存管理 + 模板 ★ FEATURED ARTICLE
༺ 个人主页 · 纪念229 ༻我的博客主页༒专栏目录《数据结构》༒༒专栏目录《算法》༒༒专栏目录《C》༒༒专栏目录《MySQL数据库》༒༒专栏目录《前端开发》༒༒其它有趣的计算机知识༒༺世上本没有路走的人多了自然就有了༻本篇文章讲述的是C内存管理和模板的内容希望对你有所帮助本篇文章主要以代码的形式讲解文章目录1.内存管理2.模板1.内存管理#includeiostreamusing namespace std;//class A//{//public:// A(int a 0)// :_a(a)// {// cout A(int a 0) endl;// }// ~A()// {// cout ~A() endl;// }//private:// int _a;//};////int main()//{// A* p5 (A*)malloc(sizeof(A) * 10);// free(p5);//// A* p6 new A[10];// delete[] p6;// return 0;//}这里讲的是malloc与new申请空间和销毁的方式之前文章解释过这里就不赘述了//#define _DEBUG_BIT//void func()//{// for (size_t i 0; i 100000; i)// {// //int* p1 (int*)malloc(sizeof(int) * 1024 * 1024); //4M// //if (p1)// //{// // cout i - p1 endl;// //}// //else// //{// // break;// //}//#ifdef _DEBUG_BIT// if (i 493)// {// int x 0;// }//#endif// int* p1 new int[1024 * 1024];//4M// //申请失败自动抛出异常// cout i - p1 endl;////这个#define XX//////// #ifdef XX //如果#define XX代码里的东西才能执行//// 代码//// #endif//// 代码里写if 条件是 i 397////目的是在里面打一个断点当我们////循环到i 397 的时候再看////用不着我们一个个点到第397次循环////不想用这段代码将#define XX注释即可////#ifdef//// 代码 不再编译//// #endif////////// }//}////int main()//{// //try/catch就是给抛异常代码的// //的接盘机制让程序死的体面//////// //try 和 catch//// 结构//// try//// {//// //可能出错的代码放这里//// }//// catch(异常类型 变量名)//// {//// //出错后处理的代码//// }////如果代码里的new失败抛异常////catch就会接收异常////并打出错在哪里//// 异常有多种举列catch()//// 这些都在小括号里//// const bad_alloc e 内存不足//// const out_of_range e 越界//// const (std::)exception e//// 继承自std::expection的标准异常//// 如std::runtime_error std::out_of_range//// 这些异常类型都在std域内//////// const ... 包含所有异常// try// {// func();// }// catch (const exception e)// {// //这里为啥不用exception e// // 原因:exception是类不加const 会触发拷贝构造// cout e.what() endl;// //代码里的what()函数是exception类的一个成员函数// //返回有错误信息的字符串// //错误信息字符串的内容由抛异常的地方决定// //// }// return 0;//}先解释main函数里的try{//代码可能出现的代码}catch(异常类型 变量名){//出错后处理的代码}一般是new申请空间失败抛异常代码里的new失败抛异常catch就会接收异常并打出异常在代码那一行异常可以是任何类型(最常见的是new抛异常类型expection)举列catch()这些都在小括号里返回意思const bad_alloc e 内存不足const out_of_range e 越界const (std::)expection的标准异常如std::runtime_error std::out_of_range(这些异常类型都在std域内)…(表示所有异常)try// {// func();// }// catch (const exception e)// {// //这里为啥不用exception e// // 原因:exception是类不加const 会触发拷贝构造// cout e.what() endl;// //代码里的what()函数是exception类的一个成员函数// //返回有错误信息的字符串// //错误信息字符串的内容由抛异常的地方决定// //// }这里为啥不用expection e 我们知道expection 这是一个类我们在形参这样写会调用拷贝构造这里what()是什么首先我们知道e是expection类类型what是该类中的成员函数作用是打印抛异常的那一行代码接下来讲解预处理指令//#define _DEBUG_BIT 这个的意思就是定义_DEBUG_BIT这个东西下面两个预处理指令配套//#ifdef _DEBUG_BIT//#endif指令后面的东西就是个名字//#ifdef _DEBUG_BITif(i493)// {// int x 0;// }//#endif我主要讲这个如果定义了_DEBUG_BIT (#ifdef _DEBUG_BIT )里面的函数就可以使用把它注释了或者没定义里面的函数就不可以用这段代码这要用于调试我们给条件语句里打一个断点等循环到这就进入条件语句代码调式停止如果不用这个代码我们想看第493次循环我们要点多少时间浪费时间//double Divide(int a, int b)//{// //当b 0时抛出异常// if (b 0)// {// string s(Divide by zero condition!);// throw s;// }// else// {// return ((double)a / (double)b);// }// cout __FUNCTION__ : __LINE__ 行执行// //这两个是宏定义标识符// //__FUNCTION__ 展开成当前行号// //__LINE__展开成当前函数名// //之前写的FUNCTION LINE// //没在左右两边各加两个下划线// //由于没有不会当成字符串// //不加的字符串会当成名字去全局里找找不到就报未定义////// endl;//}////void main()//{// int len, time;// cin len time;// try// {// cout Divide(len, time) endl;// }// catch (const string errmsg)// {// cout errmsg endl;// }这里的catch里放的string异常代码里也是throw s一般用new抛异常就会自动throw其它类型抛异常一般就是要手动throw抛异常doubleDivide(inta,intb)//{// //当b 0时抛出异常// if (b 0)// {// string s(Divide by zero condition!);// throw s;// }// else// {// return ((double)a / (double)b);// }// cout __FUNCTION__ : __LINE__ 行执行// //这两个是宏定义标识符// //__FUNCTION__ 展开成当前行号// //__LINE__展开成当前函数名// //之前写的FUNCTION LINE// //没在左右两边各加两个下划线// //由于没有不会当成字符串// //不加的字符串会当成名字去全局里找找不到就报未定义////// endl;//}这里就是防止分母为0就弄一个string类型的 sthow 就是抛异常catch就接收并打印异常原因cout __FUNCTION__ : __LINE__ 行执行这两个是宏定义标识符这两个字符串左右两边都必须各有两个下划线否则就是名字会从文件里找函数名、类名等找不到就报未定义用 就打印的是字符串作用FUNCTION展开当前行号LINE展开当前函数名//typedef int STDataType;//class Stack//{//public:// Stack(int n 4)// {// cout Stack(int n 4) endl;//// _a (STDataType*)malloc(sizeof(STDataType) * n);// if (_a nullptr)// {// perror(malloc申请空间失败);// //perror头文件#inlcudecstdio// return;// }// _capacity n;// _top 0;// }// ~Stack()// {// cout ~Stack() endl;// free(_a);// _a nullptr;// _capacity _top 0;// }//private:// STDataType* _a;// size_t _capacity;// size_t _top;//};////////int main()//{// //Stack* p1 new Stack[10];// //delete p1;//// int* p2 new int(1);// //free(p2);// delete p2;// return 0;//}这里就是通过new申请空间给空间的元素初始化然后销毁空间new比malloc多了一个自动调用构造函数delete 比free多了一个析构函数这里的delete p1;因该改为delete[] p1因为这样只会调用一次析构函数这样写在VS会报错VS较严格放在题目不会报错//class A//{//public:// A(int a 0)// :_a(a)// {// cout A(int a 0) endl;// }//// ~A()// {// cout ~A() this endl;// }// private:// int _a;//};//int main()//{// /*A* p1 new A[10];// delete[] p1;*///// A* p1 (A*)malloc(sizeof(A));// //malloc不能调用构造//// //不能这样显示调用构造// //p1-A(1);//// //要这样// new (p1)A(1);////这里的A(1)不是默认对象// //这个就是在p1内存中调用构造函数// //// // new A(1)// // 这个是申请一个空间在调用构造// //// // new (p1)A(1);// // 这个是直接在p1地址上调用构造函数// ////////// //可以析构// //p1-~A();//// free(p1);// return 0;//}malloc的对象不能自动调用构造函数可以调用析构函数要手动调用p1-~A();malloc的对象调用构造函数要调用new (p1)A(1);意思是调用构造函数传入实参1这个对象在p1这个地址中构造最后返回指针new (p1)A(1);new A(1);区别一个已有地址把构造对象放在内存一个向空间申请之后调用构造函数2.模板C模板分为函数模板类模板作用简化代码减少逻辑重复性代码我们来看看函数重载与函数模板//void Swap(int left, int right)//{// int temp left;// left right;// right temp;//}////void Swap(double left, double right)//{// double temp left;// left right;// right temp;//}////void Swap(char left, char right)//{// char temp left;// left right;// right temp;//}//函数模板//泛型编程//针对任意类型的对象交换////函数模板内容与普通函数相同时// 函数模板一般写在头文件//相同时优先用普通函数//结构//templatetypename/class 类型名// 一般用typename// void 函数名(类型名 对象名)// {// 内容//// }//templatetypename T////template不要头文件C自带//void Swap(T left, T right)//{// T temp left;// left right;// right temp;//}////int main()//{// int i 0, j 1;// double x 1.1, y 2.2;// Swap(i, j);// Swap(x, y);// return 0;//}函数重载就不赘述了就是写了交换函数函数模板结构templatetypename/class 类型名templateC自带无头文件typename/class都可以用以交换函数为例//templatetypename T////template不要头文件C自带//void Swap(T left, T right)//{// T temp left;// left right;// right temp;//}可以传任何内置类型进行交换//templateclass T//T Add(const T left, const T right)//{// return left right;//}////templateclass T1, class T2//void func(const T1 left, const T2 right)//{ }////int main()//{// int a1 10, a2 20;// double d1 10.1, d2 20.1;// //隐式实例化(实参类型推演模板参数)// cout Add(a1, a2) endl;// cout Add(d1, d2) endl;//// cout Add(a1, (int)d2) endl;// cout Add((double)a1, d2) endl;//// //显示实例化 显示指定模板参数// cout Addint(a1, d2) endl;// cout Adddouble(a1, d2) endl;// cout Addint(d1, d2) endl;// return 0;//}这里讲一下调用时如果实参类型不同或者想改变实参类型要用隐式实例化或显示实例化// //显示实例化 显示指定模板参数// cout Addint(a1, d2) endl;// cout Adddouble(a1, d2) endl;// cout Addint(d1, d2) endl;显示实例化Add(a1, d2)就是在函数名与小括号之间加个里面就是想要转换的类型隐式实例化Add(a1, (int)d2就是直接将实参隐式类型转换//专门处理int的加法函数//int Add(int left, int right)//{// return left right;////}////////通用加法函数//templateclass T////Add函数返回值是int 不是void//int Add(const T left, const T right)//{// return left right 10;//}//////int main()//{// int a1 10, a2 20;// double d1 10.1, d2 20.1;// //隐式实例化(实参类型推演模板参数)// cout Add(a1, a2) endl;// //普通函数和函数模板会进行重载协议// //若是匹配度一样的话优先用普通函数// cout Add(d1, d2) endl;// cout Addint(a1, a2);// //在匹配度相同的情况下用的(匹配度指的是比较返回值、函数名、形参)// //显示实例调用的是函数模板// return 0;//}这里讲个函数的匹配度返回类型 函数名 形参 相同就是完全匹配当函数重载和函数模板中有完全匹配的函数就会触发重载协议优先调用普通函数函数重载函数内容有差异无妨类模板//typedef double DateType;//////namespace bit//{// class stack// {// private:// DateType* _a;// int _top;// int _capacity;// };//}////int main()//{// bit::stack st1;//int// bit::stack st2;//double//// return 0;//}namespace bit{//类模板(用法与类函数差不多)templateclass Tclass stack{public://这里要加public://否则调用不了构造函数stack(intn4):_a(new T[n]),_top(0),_capacity(n){coutstack(int n 4)endl;}voidpush(constTx){//..扩容_a[_top]x;_top;}~stack(){//new申请了空间最后要销毁delete[]_a;_anullptr;_top0;_capacity0;cout~stack()endl;}private:T*_a;int_top;int_capacity;};}intmain(){try{//显示实例化bit::stackintst1;//类模板和函数模板都可以用显示实例化和隐式实例化bit::stackdoublest2;//对象通过空间构造成功后//对象就不用通过空间调用空间里的函数st1.push(1);st1.push(2);st1.push(3);st2.push(1.1);st2.push(2.2);st2.push(3.3);}catch(constexceptione){coute.what()endl;}return0;}类模板和函数模板差不多这里就不赘述了有了类模板我们想有什么类型的栈就用什么类型等…文章到此就告一段落希望对你有所帮助感谢观看
阅读完成 · 觉得有帮助?
咨询建站