C++ 内存模型

C++ 内存模型,第1张

C++ 内存模型 程序的内存分配

https://blog.csdn.net/u013007900/article/details/79338653

一个由C/C++编译的程序占用的内存分为以下几个部分:

栈区(stack)— 由编译器自动分配释放,存放函数的参数值,局部变量的值等。其 *** 作方式类似于数据结构中的栈。堆区(heap) — 一般由程序员分配释放,若程序员不释放,程序结束时可能由OS( *** 作系统)回收。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表。全局区(静态区)(static)—,全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。程序结束后由系统释放。文字常量区 —常量字符串就是放在这里的。程序结束后由系统释放。程序代码区—存放函数体的二进制代码。

int  a=0;   全局初始化区    

char *p1;   全局未初始化区    
int  main()    
{    
  int  b; //栈    
  char  s[]="abc"; //栈    
  char  *p2; //栈    
  char  *p3="123456"; //123456/0在常量区,p3在栈上。    

  static int c =0;//全局(静态)初始化区    
  p1 =  (char  *)malloc(10);  //分配得来得10和20字节的区域就在堆区
  p2  = (char  *)malloc(20);       
  strcpy(p3,"123456"); //123456/0放在常量区,编译器可能会将它与p3所指向的"123456"  优化成一个地方。    
}    

头文件

不要将函数定义或变量声明放到头文件中,如果同一程序的其他两个文件包含了该头文件,此时同一个程序将包含同一个函数的两个定义,即多重声明问题,这会导致错误。头文件常包含以下内容:

函数原型(函数声明)宏定义;#define或const定义的符号常量。结构声明类声明模板声明内联函数

源代码文件用于具体实现,即头文件中所声明的函数或类的具体实现。

注意,只需将源代码文件加入到项目中,而不用加入头文件。这是因为#include指令管理头文件。另外,不要使用#include来包含源代码文件,这样做将导致多重声明。

https://blog.csdn.net/nei504293736/article/details/90200066

模板类的分离问题:

声明和实现都写到.h文件中或者,声明写到.h中,实现写到.cpp中,同时在.cpp文件中声明具体的模板类(显式实例化)

https://www.jianshu.com/p/bd2e05aabf7a

https://stackoverflow.com/questions/495021/why-can-templates-only-be-implemented-in-the-header-file

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

有4中内存方案:

自动存储持续性,在函数定义中声明的 变量(包括函数参数)的存储持续性是自动的。它们在程序开始执行其所属的函数或代码块时被创建,在执行完函数或代码块时,它们使用的内存被释放。静态存储持续性,在函数定义外定义的变量和使用关键字static定义的变量的存储持续性都为静态。它们在程序整个运行过程中都存在。线程存储持续性,对于多线程来说,如果变量是使用关键字thread_local声明的,则其生命周期与所属的线程一样长。动态存储持续性,用new运算符分配的内存将一直存在,直到使用delete运算符将其释放或程序结束为止。这种内存的存储持续性为动态,有时被称为自由存储(free store)或堆(heap)。

作用域(scope)描述了名称在文件的多大范围内可见。可分为局部和全局,作用域为局部的变量只在定义它的代码块中可用,作用域为全局的变量在定义位置到文件结尾之间都可用。

链接性(linkage)描述了名称如何在不同单元间共享。链接性为外部的名称可在文件间共享,链接性为内部的名称只能由一个文件中的函数共享。

静态持续变量与static

程序不会使用栈或者其他来管理静态变量,而是编译器会分配固定的内存块来存储静态变量,这样这些变量在整个程序执行期间一直存在。另外如果没有显式地初始化静态变量,编译器将把它设置为默认值。

C++为静态存储持续性变量提供了3种链接性:

外部链接性,可在其他文件中访问内部链接性,只能在当前文件中访问无链接性,只能在当前函数或代码块中访问

int global = 10;  //静态持续,外部链接
static int one_file = 50;  //静态持续,内部链接
void fun1(int n)
{
    static int count = 0;  //静态持续,无链接性
    int llama = 0;
}

所有静态持续变量在整个程序执行期间都存在。fun1()中声明的变量count的作用域是局部且没有链接性,但是该变量会一直存留在内存中;global和one_file的作用域都为整个文件,而one_file的链接性为内部只能在本文件中使用它,而global的链接性为外部,因此可在其他程序文件中使用它。

extern与static

链接性为外部的变量通常简称为外部变量,它们的存储持续性为静态,作用域为整个文件。外部变量是在函数外部定义的,其也可被称为全局变量。

单定义规则(One Definition Rule, ODR):变量只能由一次定义。C++提供了两种变量声明。一种是定义声明(defining declaration)或简称为定义(definition),它给变量分配存储空间;另一种声明是引用声明(referencing declaration)或简称为声明(declaration),它不给变量分配存储空间,因为它引用已有的变量。引用声明使用关键字extern,且不进行初始化。

引用声明使用关键字extern,且不进行初始化;否则,声明为定义,导致分配存储空间。如果要在多个文件中使用外部变量,只需在一个文件中包含该变量的定义(当定义规则),但在使用该变量的其他所有文件中,都必须使用关键字extern声明它。

//file1.cpp
int a;  //定义,默认为0
static int b = 4;  // 定义,因为初始化了
const int c = 5;
extern const int d = 6;
extern int e = 7;
int fun1(int m, int n) {
    //...
}

//file2.cpp
extern int a, d, e;  //声明,因为有extern且未初始化
int b, c;  // static, const的链接性均为内部
int fun1(int, int);  //函数声明的extern可省略
其他说明符和限定符

const

声明为const的变量必须在声明的时候就初始化,并且一旦初始化后,其值就不可改变,且其声明一般是放在头文件中。const变量的链接性为内部。不过可以在定义时使用extern修饰来覆盖默认的内部链接性,将该变量的链接性为外部,

extern const int states = 50; // definition with external linkage

此时,必须在所有使用该常量的文件中使用extern关键字来声明它,这与常规外部变量不同,定义常规外部变量时,不必使用extern关键字,但在使用该变量的其他文件中必须使用extern。

mutable

mutable修饰的变量表明其无论如何是可改变的。比如一个const对象,其成员变量不可变,此时若声明某个成员变量是mutable的,则它依旧可以通过该const对象来改变该成员变量的值。

函数和链接性

所有函数的存储持续性都为静态的,即在整个程序执行期间都存在。默认情况下,函数的链接性为外部,即可以在多个文件中共享,但是在另一个文件中可以不使用extern关键字来声明函数原型,而可以直接声明函数原型即可。如果使用static关键字修饰函数,则其链接性将变为内部,此时其只能在一个文件中使用而不能在其他文件中声明和使用,必须在函数原型和函数定义中都使用该关键字,此时如果外部有同名函数,该静态函数将覆盖外部同名函数,就同局部变量覆盖全局变量一样。

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

原文地址: http://outofmemory.cn/zaji/5718943.html

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

发表评论

登录后才能评论

评论列表(0条)

保存