9 内存模型和名称空间

本章主要包括:

  • 单独编译;
  • 存储持续性、 作用域和链接性;
  • 定位(placement) new 运算符;
  • 名称空间。

9.1 单独编译

  • 有什么用:可以将程序的组件函数放在独立的一个文件中,当只修改了这一个函数,只需单独编译该函数文件,然后将它与其他文件的编译版本连接在一起,形成一个可执行的程序,这样使得大型程序管理更加方便。

  • 有好也有坏: 例如,2个文件里的函数都用到了同一个结构声明,那么两个文件都需要包含该声明,并且对其中一个文件的声明做了修改,就必须对其他文件内同一个声明做相同的修改。这样难免会遗漏和修改错误。

  • 头文件: 与其每个文件都加入声明,不如将声明放入头文件中,然后使用#inclide在每一个函数文件中包含该头文件。这样,要修改结构体声明,只需修改头文件即可。因此我们现在可以将原来的程序分为三个部分:

    • 头文件: 包含结构体声明和使用这些结构的函数原型;
    • 源代码文件: 包含与结构有关的函数代码;
    • 源代码文件: 包含调用与结构体相关的函数代码。
  • 头文件应当包含的内容:

    • 函数原型
    • 符号常量(#define 或 const)
    • 结构声明
    • 类声明
    • 模板声明
    • 内联函数
  • 如何使用头文件和源代码文件:

    • 项目只需包含源代码文件,而用#include管理头文件。
    • 不要使用#include来包含源代码文件,不然会导致多重声明。
    • 包含头文件时,应使用""而不是<>,因为这样编码器会优先在当前工作目录中查找头文件。
// coordin.h(头文件)
#include<iostream>
#ifndef COORDIN_H_
#define COORDIN_H_

struct polar
{
    double distance;
    double angle;
};

struct rect
{
    double x;
    double y ;
};

polar rect_to_polar( rect xypos);
void show_polar(polar depos);

#endif
//源代码文件(包含与头文件数据类型有关的函数代码)
#include <iostream>
#include "coordin.h"
#include <cmath>
polar rect_to_polar( rect xypos)
{   using namespace std;
    polar answer;
    answer.distance = sqrt( xypos.x*xypos.x + xypos.y*xypos.y);
    answer.angle = atan2(xypos.y, xypos.x);
    return answer;
}

void show_polar( polar depos)
{
    using namespace std;
    const double Red_to_deg = 57.29577951;
    cout<< "distance =  " <<depos.distance;
    cout<< ", angle = "<< depos.angle*Red_to_deg;
    cout<< " degress.\n";
}
//源文件(包含调用与结构体相关的函数代码)
//file1.cpp
#include <iostream>
#include "coordin.h"
int main()
{
    using namespace std;
    rect rplace;
    polar pplace;
    rplace.x = 1.5;
    rplace.y = 1.5;
    pplace = rect_to_polar(rplace);
    pplace;
    show_polar(pplace);
    cout<< "Bye!\n";

	while( cin>>rplace.x>> rplace.y)
	{
	    pplace = rect_to_polar(rplace);
	    show_polar(pplace);
	    cout<< " Next two numbers: ";
	}
    return 0;
}

distance =  2.12132, angle = 45 degress.
Bye!

 1 1

distance =  1.41421, angle = 45 degress.
 Next two numbers: 

 2 2.5


distance =  3.20156, angle = 51.3402 degress.
 Next two numbers: 

 5 
 5


distance =  7.07107, angle = 45 degress.
 Next two numbers: 

 1
 1


distance =  1.41421, angle = 45 degress.
 Next two numbers: 

 q

在这里插入图片描述

9.2 存储持续性、作用域和连接线

c++使用四种不同的方案存储数据,区别在于数据保留在内存中的时间

  • 自动存储持续性: 在程序执行到其所属的代码块时被创建,在执行完代码块后被释放。

  • 静态存储持续性: 在函数外定义的或使用关键字static定义的变量,在程序整个运行过程中都存在。

  • 线程存储持续性: 在并行编程中,由关键词thread_local声明的变量。它在其所属的线程中一直存在。

  • 动态存储持续性:new运算符分配内存开始,到delete运算符释放其内存结束。也被称为自由存储或堆。

9.2.1 作用域和链接

  • 作用域: 名称在文件的多大范围内可使用。
    • 局部作用域:只在定义它的代码块中可用;
    • 全局作用域:在名称声明开始到文件结尾都可用。
    • 函数原型作用域: 只在参数列表括号内可用,所以函数原型参数有无名称都行。
    • 类中声明的成员作用域为整个类。
  • 链接性: 名称如何在不同单元间共享。
    • 内部的:只能由一个文件中的所有函数共享;
    • 外部的: 可以在多个文件中共享。

9.2.2 自动存储持续性

函数中声明的函数参数和变量的持续性都为自动的,作用域为局部,没有链接性。

  • 程序通过栈来管理自动变量。后进先出。
  • 同名的自动变量,新定义的代替旧定义的。
#include <iostream>

void oil(int x)
{
    using namespace std;
    int a = 6;
    cout<< "In oil(), a = " << a << ", &a = " << & a << ".\n";
   cout<< "In oil(), x = " << x << ", &x = " << & x << ".\n";
    {
        int a = 7;
        cout<< "In block(), a = " << a << ", &a = " << & a << ".\n";
        cout<< "In block(), x = " << x << ", &x = " << & x << ".\n";
    }
     cout<< "pos_a = " << a << ", &a = " << & a << ".\n";
}
int main()
{
	using namespace std;
	int x = 5;
	int y = 4;
	cout<< "In main(), x = " << x << ", &x = " << &x << ".\n";
	cout<< "In main(), y = " << y << ", &y = " << &y << ".\n";
	oil(x);
	cout<< "In main(), x = " << x << ", &x = " << &x << ".\n";
	cout<< "In main(), y = " << y << ", &y = " << &y << ".\n";
	return 0;
}
In main(), x = 5, &x = 0x7f74a34f502c.
In main(), y = 4, &y = 0x7f74a34f5030.
In oil(), a = 6, &a = 0x7ffc159d4808.
In oil(), x = 5, &x = 0x7ffc159d480c.
In block(), a = 7, &a = 0x7ffc159d4804.
In block(), x = 5, &x = 0x7ffc159d480c.
pos_a = 6, &a = 0x7ffc159d4808.
In main(), x = 5, &x = 0x7f74a34f502c.
In main(), y = 4, &y = 0x7f74a34f5030.

9.2.3 静态持续变量

静态持续变量在整个程序执行期间都存在,但是提供了3种链接性:

  • 外部链接性: 声明在代码块外,可以被其他文件共享;
  • 内部链接性: 声明在代码块外,并且使用限定符static,在声明开始到文件结尾都有效,但是其他文件不可用;
  • 无链接性: 声明在代码块内,并且用限定符static。类似于局部变量,只能在声明的代码块内可用,但是一直保留到程序结束。

9.2.4 静态持续性、外部链接性

1. 单定义规则

每个使用外部变量的文件都必须声明它,但是变量只能定义一次。因此c++提供了2种声明的方法:

  • 定义声明:
  • 引用声明: 声明前使用关键字extern,且不进行初始化。

注意:单定义规则不是说不能有同名的变量,当定义了同名的局部变量,局部变量会替代全局变量
在局部变量作用内可以使用作用域解析运算符::来使用变量的全局版本

9.2.5 静态持续性、内部链接性

使用关键字static用于作用域为整个文件的变量时,该变量的链接性为内部的。这种变量只能在所属的文件全范围内可用。

  • 当定义了一个与外部变量同名的内部静态变量时,内部变量将隐藏外部变量。

9.2.6 静态持续性、无链接性

static用于作用域为代码块的局部变量,这种变量是无链接性的,即只在代码块内可用,但是一直存在于内存内。

注意:无链接性局部变量只在第一次调用时执行一次初始化。

#include <iostream>//无链接静态变量和局部变量的区别
using namespace std;
void show( int a)
{
    static  int b = 0;
    int c = 0;
    b += a;
    c += a;
    cout << " b = " << b <<", c = " << c <<".\n";
}
int main()
{ 
	int a = 1;
	show(a);//b为无链接静态变量只初始化一次,因此b每次调用都执行初始化后面的操作
	show(a);
	return 0;
}
 b = 1, c = 1.
 b = 2, c = 1.

9.2.7 说明符和限定符

  1. 存储说明符
    • auto //自动变量
    • register //寄存器存储
    • static //静态持续性变量
    • extern //外部链接变量引用声明
    • thread_local //线程存储变量
    • mutable //保留cosnt的修改性
struct data 
{
    char name[5];
    mutable int a ;//保留了a得可修改性
}

const data vvv = {"aaaa", 1};

vvv.name = "bbb";//name不可以被修改
Interpreter Error: 
vvv.a = 2;//a可以修改
  1. 限定符const
  • const全局变量的链接性是内部的,所以在头文件中的const常量可用被多个源文件包括而没有冲突。
  • 在函数或代码块中声明const时,其作用域为代码块。

9.2.8 函数的链接性

  • 函数和变量类似,但函数默认情况下为静态外部链接的。
  • 可以使用关键字static将函数链接性设置为内部的,即只在当前文件内可用,且可以定义同名的外部链接性的函数。

9.2.9 存储方案和动态分配

  1. 使用new运算符初始化
// c++98
int *pi = new int (6); //*pi set to  6;
double * pd = new double (9.9);
//c++11
int *ar = new int [4] {2,4,5,6};

9.3 名称空间

。。。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值