一、类模板
接上一节的函数模板
不管函数模板还是类模板,都是产生代码的代码。
template<class T>
class SeqStack
{
private:
T *data;
int top;
public:
SeqStack(int sz=100)
{
data=(T *)malloc(sizeof(T) * sz);
top=-1;
}
};
int main()
{
SeqStack<int> ist;
SeqStack<double> dst;
}
二、名字空间:namespace
在C++中支持域:有全局域、局部域、块域、名字空间域和类域。
#include <iostream>
using namespace std;
int g_max=10;//全局域,存放在.data
void func()
{
int x=10;//.stack 局部域
static int g_min=10;
{
int a=10;//块域
}
printf("%d",a);//error
}
名字空间域是随标准C++而引入的。它相当于一个更加灵活的文件域(全局域),可以用花括号把文件的一部分括起来,并且以关键字namespace开头给它起一个名字:
namespace YHP
{
int g_max =10;
float g_pi=3.14;
void func()
{
......
}
}
int main()
{
cout<<YHP::g_max<<endl;
YHP::func(12);
return 0;
}
名字空间的引入,主要是为了解决全局名字空间污染(定义全局变量时,发生了重复命名问题)问题,即防止程序中的全局实体名与其他程序中的全局实体名的命名冲突。
另外,只有命名空间可以套命名空间。
一个名字空间就定义了一个新的作用符,命名空间中的所有内容都局限于该,命名空间中。
三、new/delete
3.1可执行程序的虚拟地址空间
linux中.a是静态库,.os是动态库。
高地址0xFFFF FFFF
内核 |
栈(向下增长) |
共享库的内存映射区域 |
堆(向上增长) |
未初始化的数据(.bss) |
已初始化的数据(.data) |
代码(.text) |
(保留) |
低地址 0x0000 0000
#include <iostream>
using namespace std;
#include<stdio.h>
int main(int argc,char *argv[])
{
for(int i =0;i<argc;i++)
{
printf("%s\n",argv[i];
}
printf("\n");
}
这些字符串在数据区,不在堆区或者栈区。
3.2C的动态内存管理
int main()
{
int n=10;
//void * malloc(size_t size);分配size字节的未初始化内存
int *pa =(int*)malloc(sizeof(int)*n);
//void* calloc(size_t num,size_t size);
//为num个size大小的对象的数组分配内存,并将分配存储中的所有字节初始化为0
int *ipb=(int*)calloc(n,sizeof(int));
//void *realloc(void *ptr,size_t new_size);
//重新分配给定的内存区域
ipa=(int*)realloc (ipa,sizeof(int)*n*2);//追加
//
free(ipa);
}
开辟时会分配40字节,由cdcd填充,还有一个 头部由fd填充,还有一个28字节的头部,其中包含一个区域告诉计算机,分配了40字节。所以free才会知道要释放多少。
分配失败返回空指针。
3.3C++的动态内存管理
3.3.1new运算符的使用
int *ipa=new int(10);
一个空间。
底层:1.sizeof(int)计算大小 2.malloc申请分配空间 3.(10)赋值 4.将其地址返回
int *ipb=new int[10];
连续空间
11.sizeof(int)计算大小 2.malloc申请分配空间,但并不初始化 3.(10)赋值 4.将其地址返回
int n=10;
int *ipc=new int[n]{1,2,3,4,5,6,7,8};
连续空间。
delete ipa;//一个空间
delete []ipb;
delete []ipc;//释放多个空间
delete并不是将空间释放了,而是将空间还给了堆区,从引用变成为引用。
这时的指针也就变成了失效指针(失能指针)。
ipa消失是在程序结束的时候。
指针被delete之后一定要置为空。
new申请失败并不是返回一个空指针,而是抛出std::bad_alloc显示异常。
所以申请失败我们要这样写:
int func(int n)
{
int *ip=NULL;
try
{
ip=new int[n];
}
catch(std::bad_alloc &e)
{
cout<<e.what()<<endl;
}
}
或者这样写也可以,禁止他抛出异常
int *ipa=new(std::nothrow) int(10);
if(NULL==ipa)
{
cerr<<"new memony fail"<<endl;
return 1;
}
3.3.2new的函数方式使用
int main()
{
int n=100;
int *ipa=new int(10);
int *ipb=(int*)::operator new(sizeof(int));//new的函数调用
// ipb=(int*)malloc(sizeof(int));
int *ipc=(int*)::operator new(sizeof(int)*n);
delete ipa;
::operator delete(ipb);
::operator delete(ipc);
}
3.3.3定位 new
这里的定位new是定位到i所指向的空间进行初始化。
这里的new并不管你是什么类型的,只要有空间就行了。
四、auto
4.1auto类型推导
这里的z就是int
auto并不能推演出引用,除非你加了&
auto也可以和模板相结合。