数据的存储方案

来源:互联网 发布:网络拍卖许可证 编辑:程序博客网 时间:2024/03/29 10:11


原博客地址:http://blog.csdn.net/u013548531/article/details/43411385

C++中,根据数据保存在内存中的时间长短,分为四种不同的方案来存储数据。

1.自动存储持续性

2.静态存储持续性

3.线程存储持续性(C++11),不介绍。

4.动态存储持续性

—————————————————————————————————————————————————————

然而在介绍这四种不同的方案之前,先介绍两个名词。

1.作用域:描述了对象或者函数在多大的范围内可见。

2.连接性:连接性描述了变量名称如何在不同单元间共享,连接性为外部的的名称可以在文件间共享,连接性为内部的名称则只能在同一个文件中的函数共享。

—————————————————————————————————————————————————————

一、自动存储持续性


>1.自动变量(局部变量)

在函数或者代码块中声明定义的变量存储持续性为自动,作用域为局部,没有连接性,由系统栈分配内存。

自动变量具有隐藏(hide)同名变量的特性

[cpp] view plaincopyprint?
  1. int main()  
  2. {  
  3.     int number = 5;  
  4.     {  
  5.         cout << "number is: " << number << " number at: " <<&number << endl;  
  6.         int number = 10;  
  7.         cout << "number is: " << number << " number at: " <<&number << endl;  
  8.     }  
  9.     return 0;  
  10. }  

两个number虽然名称相同,但其实作用于不同,第一个number作用域一直到return语句,而第二个number从定义处开始一直到大括号,并且在第二个number作用时,第一个number被隐藏。

同样,自动变量还可以隐藏全局变量,不过可以通过作用域解析运算符来特指使用全局变量:

[cpp] view plaincopyprint?
  1. int number = 5;  
  2. int main()  
  3. {  
  4.   
  5.     {  
  6.         cout << "number is: " << number << " number at: " << &number << endl;  
  7.         int number = 10;  
  8.         cout << "number is: " << number << " number at: " << &number << endl;  
  9.         cout << "number is: " << ::number << " number at: " <<&(::number) << endl;  
  10.     }  
  11.     return 0;  
  12. }  

>2.寄存器变量:特性同自动变量,但是比普通的自动变量要快,存储在寄存器中。C++11中不在进行这种特殊处理。

二、静态存储持续性:

>1.全局变量:

全局变量也属于静态存储持续性,因为有连接性,所以作用域大大扩展,可以在多个文件中使用,由系统栈分配内存。

例如在file1中定义了一个全局变量:

[cpp] view plaincopyprint?
  1. int number = 5;//definition in file1   
可以通过外加extern关键词的方式在其他文件中使用:(这种方式称为引用声明)

[cpp] view plaincopyprint?
  1. extern int number;//use it in file2  
注意,这里不是

[cpp] view plaincopyprint?
  1. extern int number = 5;  
这种方式是对number进行了重定义,而不是引用声明。

>2.局部静态变量:

同自动变量,是在函数或者代码块中定义的变量,但是前边加有static关键词,这种局部静态变量没有连接性,作用域也只在函数或者代码块中,不同于自动变量的是,无论是否调用该函数都会事先创建该变量,静态变量不是由系统栈分配内存的,而是一块单独的内存。同时,这也意味着即使多次调用函数,静态局部变量也有且仅有一次初始化,数值被保留。

>3.全局静态变量

同全局变量,只是在变量名称前加static关键词。全局静态变量连接性为内部,只在一个文件中共享,其作用域为该文件,由专门分配静态变量的内存管理。

全局静态变量的作用很大,值得注意的是,通过全局变量可以更好的理解连接性为内部是究竟是什么意思。

情景:在多个文件中,想使用相同名称的但是初始值不同的全局变量该如何?

解决方案1:

[cpp] view plaincopyprint?
  1. int number = 5;//file1  
  2. extern int number = 10;//file2;  
由于引用变量给了初始值(10),又由于全局变量连接性为外部可以在多个文件中共享,所以这里相当于一个重定义。正确的方法应当是使用static全局变量,即:

[cpp] view plaincopyprint?
  1. int number = 5;//file1  
  2. static int number = 10;//file2,exists in file2 only  
且明显这两个number的地址是不同的。

值得一提的是,如果全局变量前加const,那么const全局变量的链接性为内部,相当于一个static静态全局变量。

内部连接性还意味着,每个文件都有自己的一组常量,而不是所有文件共享一组常量。每个定义都是其所属文件私有的,也就是能够将常量定义放在头文件中的原因。这样,只要在两个源代码文件中包含同一个头文件,那么他们就将使用同一组常量。

三、动态存储持续性

动态存储持续性,顾名思义就是使用动态内存为变量分配内存,在C++中体现的是用new与delete。

动态分配的内存,由堆来管理,它不受作用域和连接性的规则控制。

一旦被new分配内存后,只要不使用delete释放将一直存在直到程序结束。

—————————————————————————————————————————————————————

通常,new负责在堆中找到一个可以满足要求的内存块,不过C++提供了一种new运算符的变体,称为定位new运算符

定位new运算符,允许程序员手动的管理分配内存,要使用这种特性,首先要包括头文件<new>

基本的语法如下:

[cpp] view plaincopyprint?
  1. value_point = new (buffer) value_size;  
从内存池buffer中分配一块value_size这么大的内存给value_point,其中value_point是一个指针
看一个实例,能很好的明白“手动的管理分配内存”的含义。

[cpp] view plaincopyprint?
  1. #include <iostream>  
  2. #include <new>  
  3. using namespace std;  
  4. const int maxn = 512;  
  5.   
  6. int main()  
  7. {  
  8.     int buffer[maxn]= {0};  
  9.     int *p1,*p2,*p3,*p4;  
  10.   
  11.     p1 = new int[5];//use heap;  
  12.     p2 = new(buffer) int[5];//use buffer  
  13.   
  14.     cout << "heap at: " << p1 <<" static buffer at: " << (void*)buffer << endl;  
  15.     cout << "\nThe first change" << endl;  
  16.     for(int i = 0 ; i < 5 ; ++i){  
  17.         p1[i] = i * 1 + 10;  
  18.         p2[i] = i * 2 + 10;  
  19.     }  
  20.     for(int i = 0 ; i < 5 ; ++i)  
  21.         cout << p1[i] << " at " << &p1[i] << " ; " << p2[i] << " at " << &p2[i] << endl;  
  22.     cout << "\nThe second change" << endl;  
  23.     p3 = new int[5];//use heap,differ from p1  
  24.     p4 = new(buffer) int[5];//rewrite the old data,same as p2  
  25.     for(int i = 0 ; i < 5 ; ++i){  
  26.         p3[i] = i * 3 + 10;  
  27.         p4[i] = i * 4 + 10;  
  28.     }  
  29.     for(int i = 0 ; i < 5 ; ++i)  
  30.         cout << p3[i] << " at " << &p3[i] << " ; "<< p4[i] << " at " << &p4[i] << endl;  
  31.   
  32.     delete[] p1;  
  33.     delete[] p3;  
  34.     //p2,p4 can't delete  
  35.     return 0;  
  36. }  

下面是程序的运行结果:


常规new运算符与定位new运算符的不同:

1.p1,.p3是常规new运算符分配,需用delete释放。p2,p4是由buffer分配,而buffer本身是一块静态内存由栈管理,因此不可以用delete释放。

2.p2,p4是定位new运算符分配,注意实际上buffer可以为任意类型的数据分配内存(只要内存空间足够)而不一定是int类型的,且不是在堆中。

3.p3常规运算符分配,它的地址与p1不同,而p4的地址与p2是相同的

  定位new运算符使用传递给它的地址,但是不跟踪这些内存哪些已经被使用,也不查找未使用的内存,将这些内存管理的任务移交给程序员。

可以使用以下语句进行调配:

[cpp] view plaincopyprint?
  1. p4 = new(buffer + 5 * sizeof(int)) int[5];  

0 0
原创粉丝点击