C++primer plus第章--内存模型和名称空间

上帝不仅掷色子,还乱掷,没有什么是一成不变的,要做到随机应变

突然发现面对很多问题没有诀窍,正确的做法就是勇敢的正视和不断的练习努力,这样得来的时间才是改变自我完善自我的魔法。

-------------------------????

1.单独编译

编译器既编译程序也管理连接器,如果只修改一个文件,则可以只重新编译该文件,使大程序的管理更加便捷。

头文件的合理性在于要修改结构时只需要在头文件中改动一次即可(分层次是一种混乱到有序的必然趋势)。

可以将原来程序分为三个部分:

  • 头文件:包含结构声明和使用这些结构的函数的原型
  • 源代码文件:包含与结构有关的函数的代码
  • 源代码文件:包含与调用函数有关的函数的代码(包括main())

不要将函数定义放在头文件中,除非是内联函数,也可以将const数据放在头文件中,他们有特殊的连接属性。

如果文件名用尖括号,在文件系统中查找,用双引号,首先在源代码目录中查找。

在同一个文件中只能包含一个头文件一次,可以使用

#ifndef filename

#define filename

#endif

这种方法并不能防止编译器将文件包含两次,而是让他忽略。

2.存储持续性,作用域,链接性

  • 自动存储持续性(栈,代码块)
  • 静态存储持续性(固定的内存块,在程序执行期间存在,没有初始化的话默认为0)
  • 线程存储持续性(C++11,和线程一样长)
  • 动态存储持续性(堆,指针,自己管理)

C++11中的auto为自动类型推断,但c语言和以前C++,auto显示指出变量为自动存储。(设计语言设计者的选择问题)

C++11中的register显示指出变量是自动的,但c语言和以前C++,auto显示指出变量为CPU寄存器存储的自动变量,提高访问速度,保留这个关键字的原因是避免现有代码非法。

C++primer plus第章--内存模型和名称空间

C++提供两种变量声明

1.定义声明,给变量分配空间

2.引用声明,不分配内存空间

由于单定义规则,在其它文件中使用链接性为外部的全局变量时用extern(即引用声明).

c++提供作用域解析运算符 ::,放在变量名前使用全局版本。

const限定符使全局变量的链接性为内部,如果处于某种原因,希望某个常量的链接性为外部的,可以使用extern关键字来覆盖默认的内部的链接性,extern const int xixi=40;在这种情况下。必须使所有使用该常量的文件使用extern关键字来声明它。另外,只有未使用extern关键字的声明才能初始化,且只能初始化一次,当然由于实现,一些编译器也能通过,但会警告。

C++primer plus第章--内存模型和名称空间

C++primer plus第章--内存模型和名称空间

注意避免二义性!

3.函数和链接性

和变量一样,函数也有链接性,虽然可选择的范围比变量小。

所有函数的存储持续性都自动为静态的(即整个程序执行期间都一直存在),在默认情况下,函数的链接性为外部的,可以在文件间共享,实际上,可以在函数原型中使用关键字extern来指出函数在另一个文件中定义的,不过这是可选的,即默认如此。

static用于函数时,原型和定义中都要使用该关键字。

静态函数将在本文件中查找,否则在所有程序文件中查找。

4.语言链接性

链接程序要求每个不同函数都有不同的符号名,可以在函数原型中指出要使用的约定。

extern "C" void spiff(int);          //use C protocol for name look-up

extern "C++" void spaff(int);    //use C++ protocol for name look-up

extern void spoff(int)               //use C++ protocol for name look-up

5.存储方案和动态分配

动态内存由运算符new和delete控制,而不是由作用域和链接性规则控制。

程序结束后,有new分配的内存通常被释放,但在不健壮的操作系统中可能做不到,最好符合规范。

1.使用new运算符初始化

内置类型可直接用括号,结构或数组需要大括号的列表初始化(需要支持C++11,C++11新特性);

int* a=new int[4]{1,2,3,4};

2.new失败时,可能找不到请求的内存量,在最初的十年,C++返回空指针,现在将发生异常 std::bad_alloc(可见一个语言总是在发展过程中不断完善自己)。

3.运算符new和new[]分别调用如下函数:

void* operator new(std::size_t);

void* operator new[](std::size_t);

同样delete和delete[]也有释放函数,他们位于全局名称空间中,delete只能用于这样的指针:指向常规new运算符分配的堆内存

可见这些关键字实质是一些函数的替换。

4.定位运算符new.要使用定位new特性,首先要包含头文件new,常规new函数区别在于参数的数目,他们返回的指针为void*,以便能够赋给任何指针类型。

int* p1=new int;                     //invokes new(sizeof(int))

int* p2=new(buffer) int;         //invokes new(sizeof(int),buffer)

int* p3=new(buffer) int[40];         //invokes new(40*sizeof(int),buffer)

5.名称空间

1.传统名称空间

声明区域和潜在作用域

2.新的名称空间特性(开放性)

提供一个声明名称的区域,名称空间可以是全局的,也可以位于另一个名称空间,但不能位于代码块中,默认情况下,在名称空间中的名称的链接性为外部的(除非它引用了常量)。

using声明和using编辑指令区别:如果函数中存在了相同的名称,则不能使用using声明,但可以用using编辑指令,只是被隐藏了,从安全性上来说,using声明更佳。

可以给名称空间起别名  namespace xixi=my_very_favorite_things;方便编程;

未命名的名称空间相当于链接性为内部的静态变量的替代品。