内联
函数调用流程:
程序执行顺序转移到函数所存放的内存中某个地址,将函数的程序内容执行完后,再返回到调用函数前的地方。要达到这样的目的必须在转去前,保护现场并存储执行的地址,转回后先恢复现场,并按照原存储地址继续执行。因此,函数调用有一定的时间和空间方面的开销,影响其效率。特别是对于一些函数体不大,但又频繁的调用的函数来讲,解决其效率问题更重要。
内联目的:
目的:解决因反复调用函数在时间和空间上的开销,影响其效率。
本质:编译时函数体中的代码被替代到程序中(空间换时间)
编译选项:
就算没有inline,编译器都会尝试编译成内联。提高效率,空间换效率,但是会不会内联成功不会告知
● /Ob0 取消内联关键字生效
● /Ob1 有关键字或满足其他语法,且内联不保证生效
● /Ob2 不管什么时候都尝试内联。
内联注意:
1.类内定义的函数是内联函数,类外定义的函数是非内联函数(短函数可以 定义在类内,长函数可以定义在类外)。
2.可以为类外定义的函数指定 inline ,强行为内联函数。
3.在内联函数内不允许用循环语句和复杂语句。
4.内联的定义必须出现在内联函数第一次被调用之前。
this指针
由于名称粉碎机制的存在,成员函数在编译的时候,会编译成一个全局函数。那么编译器是如何知道这个成员数据在哪里呢?
机制:在函数传递参数的时候,隐含传递了一个本类型的指针,this指针(对象本身的地址)。
this指针属性:指向本对象,且不可修改的指针
inline char* CMyString::SetString(/* CMyString const this ,/char* pszNew)
//隐含传递了一个CMyString的指针,this指针(对象本身的地址)
this指针与其他指针不同的地方:
不能监视窗口查看其值,(this指针存在寄存器中)
this指针不能更改,且只能指向对象本身。
new 和 delete
本质:new 内部会使用 _nh_malloc( cb , 1 ) 申请空间,当对象为类时,成功申请后自动调用合适的构造函数。
new 对象数组[]
机制:new对象数组的时候,在 &指针地址-4byte处存了一个计数器。
delete 对象数组
机制:对象数组delete的时候通过st2指针找到类型CMYString,对其类型求sizeof。
然后找到起始位置 - 4byte 得到count 乘 sizeof单个对象的大小,定位到最后一个对象,- 4字节处开始调用析构。
然后调用free 释放内存,且按照new的前后顺序,倒序释放。因为对象1不能依赖对象2,所以必须从后面开始释放。
有几个对象就要调用几个析构、
释放顺序:且按照new的前后顺序,倒序释放,因为对象1不能依赖对象2,所以必须从后面开始释放。
当对象是类时:会先调用析构函数,然后内部会使用free释放空间
delete常见崩溃
情况1:delete 对象数组
delete[] 释放单个对象崩溃的原因:释放的时候,把单个对象当做数组,此时对象的地址没变,去-4byte找count,由于此时没有count,读取到的是上溢标志FDFDFDFD次数来释放,这个次数太大了。
情况2:delete[] 对象
delete[] 释放单个对象崩溃的原因:释放的时候,把单个对象当做数组,此时对象的地址没变 去-4byte找count, 由于此时没有count,读取到的是上溢标志FDFDFDFD次数来释放,这个次数太大了。
const
编译器先扫描:以为界限,前面的修饰前面部分,后面的修饰右边变量
inline char CMyString::SetString(/* const CMyString const this ,/char* pszNew) const
//后面加const 编译器理解为:const CMyString const *this 。目标和指针都不能改
类中适合const的成员函数:
适合不更改this指针的成员函数:GetString() const、GetLength()const
附加:中缀转后缀
eg:a+b*c-d/e
国语解释:a与bc之积,与de之商求差。
转换为汇编:sub(add(a,mul(b,c)),div(d,e))
编程求:二叉树中序遍历
附录:
include
include "CMyString.h"
include <string.h>
using namespace std;
/**********************************************************************
- 就算没有inline编译器都会尝试编译成内联。提高效率,空间换效率,但是会不会内联成功不会告知
- DeBug环境下。内联失效/Ob0
- /Ob0 取消内联关键字生效
- /Ob1 有关键字或满足其他语法,且内联不保证生效
- /Ob2 不管什么时候都尝试内联。
*属性:
- 类内的函数都默认内联。
**********************************************************************/
inline int MyMax(int x, int y)
{
return x > y ? x : y;
}
//运行时常量 ,编译时常量
int const n = 666;
int main()
{
int* p3 = (int*) & n;
//*p3 = 999; //ERROR:编译不通过,引发了异常: 写入访问权限冲突。cout << n << endl; //输出还是666 的原因:常量传播。编译的时候,编译器扫描。发现n是常量,直接替换成n参加编译。CMyString str;
//指针会破坏类的封装性int* p = (int*)&str; //说明不能访问是语法层面的限制:编译器限制
cout << *p << *(p + 1) << endl;//?SetString@CMyString@@QAEPADPAD@Z (&str,"Hello world");//后台调用。
str.SetString((char*)"world");
/*********************************************************************
- new 和delete 属于运算符,可以通过运算符重载自定义其行为。
- new 内部会使用 _nh_malloc( cb , 1 ) 申请空间,成功申请后自动调用合适的构造函数。
- delete 会先调用析构函数,然后内部会使用free释放空间。
*********************************************************************/
int pn = new int;
/**********************************************************************
- 情况①:delete 单个对象
**********************************************************************/
CMyString st1 = new CMyString((char*)"Hello");
delete st1; //由代理函数调用析构函数,在调用free,debug版本下是free_dbg
/**********************************************************************
- 情况②:delete[] 对象数组
- 在delete对象数组的时候,编译器是如何知道new了几个对象呢?
- 机制:delete 单个对象和对象数组的方式不一样。
- 其根本在于,new对象数组的时候,在 &指针地址 -4beyt处存了一个计数器。
- delete[] 对象数组d的时候通过st2指针找到类型CMYString,对其类型求sizeof。
-
然后找到起始位置 - 4byte 得到count 乘 sizeof单个对象的大小,定位到最后一个对象,- 4字节处开始调用析构。
-
然后调用free 释放内存,且按照new的前后顺序,倒序释放。因为对象1不能依赖对象2,所以必须从后面开始释放。
-
有几个对象就要调用几个析构、
- delete释放对象数组造成崩溃的原因:吧count后面的字节当做堆数据区,此时不是堆数据的地址。
(解析堆的信息出错)解析堆的时候附加数据读取乱套。 - delete[] 释放单个对象崩溃的原因:释放的时候,把单个对象当做数组,此时对象的地址没变 去-4byte找count,
-
由于此时没有count,读取到的是上溢标志FDFDFDFD次数来释放,这个次数太大了。
**********************************************************************/
CMyString st2 = new CMyString[5];
delete[] st2;
/**********************************************************************
- const
- 编译器先扫描:以为界限,前面的修饰前面部分,*后面的修饰右边变量
**********************************************************************/
return 0;
}