
名字空间域的引入,主要是为了解决全局名字空间污染(global namespace pollution)问题,即
防止程序中的全局实体名与其他程序中的全局实体名,命名冲突。
在C++中支持三种域:局部域、名字空间域和类域。
- 普通的命名空间
//TestMain.cpp
//
namespace yhp
{
int g_max = 10;
int g_min = 0;
int my_add(int a,int b){ return a+b;}
}
2.名字空间域可分层嵌套,同样有分层屏蔽作用
//
namespace Primer
{
double pi = 3.1415926535898;
double my_add(double a,double b) { return a + b;}
namespace Matrix
{
char my_max(char a,char b) { return a>b? a:b;}
}
}
- 同一个工程中允许存在多个相同名称的命名空间
// 编译器最后会合成同一个命名空间中。
namespace yhp
{
float pi = 3.14;
int my_sub(int a,int b)
{
g_min = a - b;
return g_min;
}
}
1.作用域限定符::的使用
int main()
{
std::string s;
std::vector<int>v;
int a = yhp::my_add(12,23);
printf("%lf n",Primer::pi);
printf("%f n", yhp::pi);
Primer::Matrix::my_max('a','b');
return 0;
}
2.using 替代typedef 类型重命名
new (buff) int(10); //1关键字 char* p = new char("a") 2函数用法3.定位new
new(buff)int[] {1, 2, 3};
using u_int8 = unsigned char;
using pfun = int(*)(int, int);
using cc = char[3];
int main()
{
cc a;
cc b;
}
二、new 代替malloc函数
1.栈和堆的区别
realloc函数
int* ip = (int*)malloc(sizeof(*ip) * n);//*ip 也是int型
2.在下面的情况中当我们realloc申请空间成功后释放了原地址 将会发生什么?
int*p=(int*)malloc(sizeof(int)*n);
int *newdata=realloc(p,sizeof(int)*n*10);
if (newdata == NULL)
return false;
if (newdata != NULL)//如果我想保留free(p),我把if语句改成if(newdata!=NULL);RETURN FALSE; if(newdata!=p)可不可以?
{
free(p);.//我们释放了原来的地址(错误代码)
p= newdata;
}
else
}
realloc申请扩容时,(1)系统会考虑余下连续的空间内大小是否足够,(2)不够会找不相邻的其他空间。如果我们申请的空间的情形是前一种,也就是说我们申请的空间地址还是之前的p,那么free§,把p指向的扩容空间删除掉,那么那块空间的地址就丢失掉了,再也找不到了。
所以我们不要free(p),而是把newdata的地址给p(其实作用 于第(2)种情况,当然也涵盖情况(1))。
1、计算类型大小,2.malloc申请空间 3. 初始化4.返回地址
int main()
{
int n = 10;
int* ipa = new int(10); // 1 // 2;
int* ipb = new int[n](10);
int* ipc = new int[n] {1, 2, 3, 4, 5, 6, 7};
delete ipa;
delete[]ipb;
delete[]ipc;
return 0;
}
1.new作为关键字
char* p = new char('a');
int main()
{
int** p = (int**)malloc(sizeof(int*) * 10);
p = new int* [10]{ NULL };
}
new空间申请失败 程序出现异常 (不会反回空指针) throw bad alloc
int *S=new (nothrow)int [10]; 加上nothrow 如果申请失败返回空指针。
2.new 函数的用法:
int * s =(int *)::operator new(sizeof(int)*10,nothrow);//
类似malloc了 加上noththrow 开辟失败返回空指针,但是不能初始化
::operator 开辟空间
int main()
{
int n = 10;
int *ipa = (int*)::operator new(sizeof(int));
// (int*)malloc(sizeof(int));
int *ipb = (int*)::operator new(sizeof(int)*n);
// (int*)malloc(sizeof(int)*n);
::operator delete(ipa);
::operator delete(ipb);
return 0;
3.定位 new
不开辟空间 在地址上根据你的要求初始化
new (buff) int(10); //1关键字 char* p = new char("a") 2函数用法3.定位new
new(buff)int[] {1, 2, 3};
下面是new初始化导致越界的问题
char buff[10]={0};
char *P=(char*)malloc(sizeof(char)*10);
if(p==NULL) return 1;
new(p)double[]{1,2};
free(p);
此时new double 16个字节大于了之间p指向的10个字节,所以越界,越界标记丢失。
1.编译器怎么判断变量内存上是否越界?
越界和下越界标记(fdfdfdfd)丢失(被数据冲刷掉了)
对于内置类型 new / delete / malloc/free 可以混用。
区别:
1、 new/delete 是C++中的运算符。 malloc / free 是函数。
2、 malloc申请内存空间时,手动计算所需大小,new只需类型名,自动计算大小;
3、 malloc申请的内存空间不会初始化,new可以初始化;
4、 malloc的返回值为void*, 接收时必须强转,new不需要;
5、 malloc申请内存空间失败时,返回的是NULL,使用时必须判空;
new申请内存空间失败时抛出异常,所以要有捕获异常处理程序;、
1.类型推导
C++11引入了auto 和 decltype 关键字实现类型推导,通过这两个关键字不仅能方便地获取复杂的
类型,而且还能简化书写,提高编码效率。
C11 中 auto 成为类型指示符(type-specifier)。
auto类型推导:auto 定义的变量,可以根据初始化的值,在编译时推导出变量名的类型。
int main()
{
auto x = 5; // ok x 是 int类型
auto pi = new auto(1); // ok pi 被推导为int *;
const auto *xp = &x, u = 6; // ok xp是const int*类型,u是const int类型
static auto dx = 0.0; // ok dx 是 double 类型
auto int b; // error C11 中 auto不再表示存储类型指示符
auto s ; // error 没有初始化值 auto无法推导出s的类型
}
auto推演变量类型
auto 可以在函数识别类型时很方便:
int main()
{
auto x = Max(12, 23);
auto c = Max('a', 'b');
}
当然也可以通过函数模板 来方便识别变量的类型。
auto 可以推演常性(const)
volatile 易变关键字:
,编译器对访问该变量的代码不再进行优化,从而可以提供对特殊地址的稳定访问。
(当寄存器 高速缓存中存储的常用数据读取时 改变到从内存读取。)
auto 并不能代表一个实际的类型声明(如s的编译错误),只是一个类
型声明的"占位符"。
使用 auto 声明的变量必须要有初始化值,以让编译器推断出它的实际类型,并在编译时将auto 占位符替换为真正的数据类型。
auto作为函数的形参类型
void func(auto x)
{
cout << sizeof(x) << endl;
cout << typeid(x).name() << endl;
}
int main()
{
int a = 10;
int ar[]={12,23,34,45,56};
fun(a);
fun(ar);
}
void funr(auto &x)
{
cout << sizeof(x) << endl;
cout << typeid(x).name() << endl;
}
int main()
{
int a = 10;
int ar[]={12,23,34,45,56};
fun(a);
fun(ar);
}
auto 的限制 :无法推演数组类型当然也无法推演结构体
auto总结:
1、C11 中 auto 成为类型指示符(type-specifier)。
1、auto不能用于函数参数。
2、auto不能用于非静态成员变量
3、 auto 无法定义数组
4、 实例化模板时不能使用auto作为模板参数。
decltype
容器:容纳对象的对象
基于范围的for()循环
一般格式:
for(ElemType val: array) { ...// statement 循环体 }
ElemType:是范围变量的数据类型。它必须与数组(容器)元素的数据类型一样,或者是数组元素可以自动转换过来的类型。
上图中 的for(int &val:ar) 与(int val :ar)对结果的影响: 前者的ar数组的值发生 了++的改变。
如下程序为我们展示了用auto自动识别类型时,基于范围的for循环里elemtype参数可以为auto 自动识别x 形参的元素类型。
思考一下,为什么在Print函数形参中的x 要加上&呢?
加上引用符号就可以减少内存开辟,减少了开销,因为引用本质并没有copy
嘛。我们可以尝试用代码试验一下结果是否一致。
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)