C++ primer plus 内存模型和命名空间

第9章 内存模型和命名空间

P300 单独编译

一个程序可分为三部分:

  • 头文件:包含结构声明和使用这些结构的函数的原型
  • 源代码文件:包含与结构有关的函数的代码
  • 源代码文件:包含调用与结构相关的函数的代码
    注意不要将函数定义或变量声明放在头文件中
#ifndef COORDIN_H_
#define COORDIN_H_

#endif // !COORDIN_H_

使用这样的编译情况可以防止代码被包含两次

P304 存储持续性、作用域和链接性

C++中使用四种不同的方案来存储数据:

  • 自动存储持续性:函数中定义的变量其生存周期仅为函数执行过程中,执行完后其内存将会被释放
  • 静态存储持续性:用static修饰的变量,其生存周期为整个程序运行期间
  • 线程存储持续性:使用thread_local声明的,其生命周期与所属线程一样长
  • 动态存储持续性:用new与delete搭配的变量,有时被称为自由存储或堆。

作用域和链接性

链接性为外部的名称可在文件之间共享,链接性为内部的名称只能由一个文件中的函数共享。自动变量没有链接性,因此不能被共享。

自动存储持续性

栈:在函数运行伊始,函数首先将参数值压入栈中,被调用的函数根据其形参描述来确定每个参数的地址。并将其与变量名相关联,在函数结束后,变量并不会被删除,但栈指针将会下移,在之后的函数运行时被覆盖。
关键字register用来修饰变量类型,将变量放在寄存器中,旨在加快运行速度。如:register int count_fast;

静态持续变量

C++为静态持续变量提供了三种链接性:外部链接性、内部链接性、无链接性。请看如下代码示例:

int global = 1000;//外部链接性
static int one_file = 50;//内部链接性

void func1(int n) {
	static int count = 0;//无链接性
}

静态持续性、外部链接性

  1. 单定义规则
    在每个使用外部定义的文件中,应在声明之外的使用处使用extern修饰,否则则为二次定义。如:extern int cats
#include<iostream>
using namespace std;

double warming = 0.3;
void update(double dt);
void local();

int main() {
	cout << "全局warming是" << warming << endl;
	update(0.1);
	cout << "全局warming是" << warming << endl;
	local();
	cout << "全局warming是" << warming << endl;
	return 0;
}
#include<iostream>
using namespace std;

extern double warming;

void update(double dt);
void local();

void update(double dt) {
	extern double warming;
	warming += dt;
	cout << "更新全局warming为" << warming << endl;
}

void local() {
	double warming = 0.8;
	cout << "本地warming为" << warming << endl;
	cout << "但是全局warming为" << ::warming << endl;
}

将上方两个文件链接,注意到下面代码倒数第二行的“::”,它是域解析运算符,将该运算符放于变量前,可使用变量的全局版本。
下面再看一段代码(感觉用法比较重要所以记一下)

#include<iostream>
using namespace std;

const int ArSize = 10;
void strcount(const char* str);

int main() {
	char input[ArSize];
	char next;
	cout << "输入一行\n";
	cin.get(input, ArSize);
	while (cin) {
		cin.get(next);
		while (next != '\n')
			cin.get(next);
		strcount(input);
		cout << "输入一行,空行时停止\n";
		cin.get(input, ArSize);
	}
	cout << "拜拜" << endl;
	return 0;
}

void strcount(const char *str) {
	static int total = 0;
	int count = 0;
	cout << "\"" << str << "\"包含";
	while (*str++)
		count++;
	total += count;
	cout << count << "个字符\n";
	cout << total << "个字符总共\n";
}

这段代码利用了这样一个事实,即试图使用get(char *,int)读取空行将导致cin为false。

说明符和限定符

  1. volatile
    这个关键字表明,及时程序代码没有对内存单元进行修改,其值也可能发生变化。将变量声明为volatile将会防止程序发生将变量存储于寄存器中这一优化过程。
  2. mutable
    mutable可以指出即使结构或类是const,其某个成员也可以被修改。
struct data {
	char name[30];
	mutable int accesses;
};

const data veep = { "a",8 };
strcpy(veep.name, "b");//错误
veep.accesses++;//允许
  1. const
    const全局变量的链接性是内部的,但可以通过extern来改变其链接性如:extern const int states = 50 ;
    使用一个函数的每个文件都应包含函数原型。

存储方案和动态分类

使用new进行动态分配,可以在类型名后面加上初始值,并用括号括起:int *pi = new int (6)。这也适用于结构或数组。
当使用new失败时,将会返回一个空指针。
定位new运算符:可以将new申请在一个确定的位置,如下所示:

char buffer1[50];
p1 = new (buffer1) chaff;

把chaff放在buffer1的位置上。但这种情况下就不能使用delete来删除内存了,因为buffer存放的位置在静态内存,而不是new运算符常规指向的堆内存。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Godams

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值