C++ essential(day 1)

 

  1. 对于一个完整的程序,在内存中的分布情况如下图: 
    1. 栈区: 由编译器自动分配释放,像局部变量,函数参数,都是在栈区。会随着作用于退出而释放空间。栈由系统自动分配,速度较快,在windows下栈是向低地址扩展的数据结构,是一块连续的内存区域,大小是2MB。
    2. 堆区:程序员分配并释放的区域,像malloc(c),new(c++) 。堆需要程序员自己申请,并指明大小,速度比较慢。在C中用malloc,C++中用new。另外,堆是向高地址扩展的数据结构,是不连续的内存区域,堆的大小受限于计算机的虚拟内存。因此堆空间获取和使用比较灵活,可用空间较大。
    3. 全局数据区(静态区):全局变量和静态变量存储是放在一块的,初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。程序结束释放。
    4. 常量区:存放常量(程序在运行的期间不能够被改变的量,例如: 10,字符串常量”abcde”, 数组的名字等) 
    5. 代码区
  2. Static
    1. 局部静态变量:虽然在函数内部,但是储存于全局数据区,只初始化一次,即使在不同函数被调用的过程中,仍然持续存在,不会被被破坏又被建立,
    2. 该变量在全局数据区分配内存(局部变量在栈区分配内存);
    3. 静态局部变量在程序执行到该对象的声明处时被首次初始化,即以后的函数调用不再进行初始化(局部变量每次函数调用都会被初始化);
    4. 静态局部变量一般在声明处初始化,如果没有显式初始化,会被程序自动初始化为0(局部变量不会被初始化);
    5. 它始终驻留在全局数据区,直到程序运行结束。但其作用域为局部作用域,也就是不能在函数体外面使用它(局部变量在栈区,在函数结束后立即释放内存);
      int f(int n){
          static int i=1;
           if(n>=5)
               return n;
           n=n+i;
           i++;
           return f(n);
      }
      //输出7

       

  3. new
    1. 自动存储,也叫做自动变量,比如int num = 10; 这个num就属于自动变量。所谓自动,代表它会自动申请内存,也会自动释放内存,自动变量是保存在栈里的(后进先出)。 如果大家觉得很难理解,那么,换一个名称——局部变量。局部变量在离开函数,或者离开它所属的代码块之后,就会被释放。而Value v = Value(100); 、int num = 10; 这些都是局部变量,一旦离开函数或者离开它的作用域,就会被释放。比如把int num; 作为成员变量,那么,在这个类被释放的时候,num变量也会被释放。这就是为什么我们在创建了这么多int、float等基本类型的变量之后,不需要去释放它们。因为它们是自动被释放的。
    2. 动态存储:
      1. 自动变量有很大的好处,那就是不需要我们去管内存方面的事情,但是,有时候我们不希望有这样的自动释放内存。我们希望自己去控制什么时候释放对象,这时候就要用到new了。
      2. 我们都知道,new了之后,如果不调用相应delete的话,申请到的内存空间是永远都不会被释放的。这就是动态存储了,我们自己来申请内存,自己来释放内存。
      3. 当然,内存泄露的罪魁祸首之一也正是new~!
      4. 因为正常人都会有疏忽的时候,并且当程序足够庞大、逻辑足够复杂的时候,有些地方调用了new,却疏忽了delete是再正常不过了。
    3. new的特性
      1. new创建类对象需要指针接收,一处初始化,多处使用
      2. new创建类对象使用完需delete销毁
    4. new创建对象直接使用堆空间,而局部不用new定义类对象则使用栈空间
    5. new对象指针用途广泛,比如作为函数返回值、函数参数等
    6. 频繁调用场合并不适合new,就像new申请和释放内存一样
  4. 默认参数:
    1. 方便提供不同的解决方式
    2. 如果为一个参数提供了默认参数,那么这个参数右边的所有参数必须添加默认值。
  5. Reference
    1. 引用&必须指定一个对象,不能像pointer一样为空
    2. 对于reference,在函数中设定了一个默认值,那么这个默认值右边的所有值必须设定默认值。
    3. 对于reference,只能制定一次,不在函数声明处,则在函数定义处。一般放在声明处,便于阅读代码。
  6. inline函数的作用
    1. 在系统下,栈空间是有限的,假如频繁大量的使用就会造成因栈空间不足而导致程序出错的问题,如,函数的死循环递归调用的最终结果就是导致栈内存空间枯竭。
    2. 为解决这个问题,引入一个内联函数inline。
    3. 对于简单的,内部没有复杂的while,for循环等结构,本身不是递归函数的函数,可以声明为inline
    4. inline函数仅仅是一个对编译器的建议,所以最后能否真正内联,it depends,计算机如果认为函数不复杂,能在调用点展开,就会真正内联,并不是说声明了内联就会内联。
    5. 类中的成员函数与inline:

      定义在类中的成员函数缺省都是内联的,如果在类定义时就在类内给出函数定义,那当然最好。如果在类中未给出成员函数定义,而又想内联该函数的话,那在类外要加上inline,否则就认为不是内联的。

    6. 声明跟定义要一致:如果在每个文件里都实现一次该内联函数的话,那么,最好保证每个定义都是一样的,否则,将会引起未定义的行为。如果不是每个文件里的定义都一样,那么,编译器展开的是哪一个,那要看具体的编译器而定。所以,最好将内联函数定义放在头文件中。

    7. 关键字inline 必须与函数定义体放在一起才能使函数成为内联,仅将inline 放在函数声明前面不起任何作用

    8. 以下情况不宜使用内联: 
      (1)如果函数体内的代码比较长,使用内联将导致内存消耗代价较高。 
      (2)如果函数体内出现循环,那么执行函数体内代码的时间要比函数调用的开销大。类的构造函数和析构函数容易让人误解成使用内联更有效。要当心构造函数和析构函数可能会隐藏一些行为,如“偷偷地”执行了基类或成员对象的构造函数和析构函数。所以不要随便地将构造函数和析构函数的定义体放在类声明中。一个好的编译器将会根据函数的定义体,自动地取消不值得的内联(这进一步说明了 inline 不应该出现在函数的声明中)。

    9. 本部分引用自https://www.cnblogs.com/fnlingnzb-learner/p/6423917.html,十分感谢

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值