【命名空间、new 开辟空间、auto推演变量类型、基于范围的for循环】

【命名空间、new 开辟空间、auto推演变量类型、基于范围的for循环】,第1张

一 名字空间 :namespace

名字空间域的引入,主要是为了解决全局名字空间污染(global namespace pollution)问题,即
防止程序中的全局实体名与其他程序中的全局实体名,命名冲突。

在C++中支持三种域:局部域、名字空间域和类域。

  1. 普通的命名空间
//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;}
 }
}

  1. 同一个工程中允许存在多个相同名称的命名空间

// 编译器最后会合成同一个命名空间中。
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
嘛。我们可以尝试用代码试验一下结果是否一致。

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/langs/921572.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2022-05-16
下一篇2022-05-16

发表评论

登录后才能评论

评论列表(0条)

    保存