类和对象+内存管理 4.18

1.匿名对象

我们平时定义的就叫有名对象

那么他们有什么区别呢 在如图中的有名对象的生命周期是他们的作用域  而匿名对象的生命周期只有当前的这一行 可以说是即用即销毁

并且匿名对象是具有常性的

意义:

这里上面两行是使用有名对象创建  下面的一行是使用匿名对象  这里看的话明显是匿名对象比较方便 也就是说 匿名对象在一些特定情况下创建变量是要比有名对象更加方便的

2.对象拷贝的一些优化

2.1传值传参:

这里解释一下 第一个构造函数 是A aa1引起的

                       第二个拷贝构造是因为调用f1函数时进行传值传参 而传值传参会引发拷贝构造  

                        第三个析构函数时因为f1结束对形参aa进行析构

                         第四个析构函数是因为main函数结束 对aa1进行析构

2.2引用传参

这里使用引用传参可以省略拷贝构造 

并且这里建议是使用const去修饰引用传参的 因为像上图中传匿名对象 和 进行隐式类型转换 他们都会带有常性去传参 这样可以防止造成权限的扩大

2.3    连续一个表达式中 构造加拷贝构造 会直接优化为构造

2.4传值返回

class A

{
public:
	A(int a = 0)
		:_a(a)
	{
		cout << "A(int a)" << endl;
	}
	A(const A& aa)
		:_a(aa._a)
	{
		cout << "A(const A& aa)" << endl;
	}
	A& operator= (const A& aa)
	{
		cout << "A& operator= (const A& aa)" << endl;
		if (this != &aa)
		{
			_a = aa._a;
		}
		return *this;
	}	
	~A()
	{
		cout << "~A()" << endl;
	}

private:
	int _a;
};
void f1(const A  aa)
{

}
A f2()
{
	A aa1;
	return aa1;
}
int main()
{
	A aa2 = f2();
	cout << endl;
	return 0;
}

这里按正常情况下 应该是f2中首先进行构造 创建对象aa1 之后传值返回会通过拷贝构造产生临时变量 之后 aa2通过拷贝构造进行接收

但是编译器会进行优化 在一个表达式中 会将连续的两个拷贝构造进行优化为一个拷贝构造

2.5拷贝构造+拷贝赋值重载

这里的拷贝构造加拷贝赋值是不会产生优化的 建议不要这样写

甚至这里在更高版本的vs或者release版本下 会进行更强的优化  对比上面会直接省去一个拷贝构造

这里是将整个f2当做一个构造来充当临时对象来使用  而且f2产生临时变量的生命周期也发生了改变 它是在赋值以后才进行销毁的

    3.理解类和对象

类是对某一类实体(对象)来进行描述的,描述该对象具有那些属性, 那些方法,描述完成后就形成了一种新的自定义类型,才用该自定义类型就可以实例化具体的对象。     

4关于析构顺序 和构造顺序

这里最先构造的是全局对象aa0 之后是局部对象aa1 aa2 最后是静态对象aa3 

在main函数 中产生aa1 和 aa2 这两个他们是在栈中 满足后进先出的规则 所以aa2后定义 aa2先析构   而aa1先定义 所以aa1后析构 

4.c/c++内存分布

 4.1 栈又叫堆栈--非静态局部变量/函数参数/返回值等等,栈是向下增长的。

4.2. 内存映射段是高效的I/O映射方式,用于装载一个共享的动态内存库。用户可使用系统接口创建共享共 享内存,做进程间通信。(现在只需要了解一下)

4.3. 堆用于程序运行时动态内存分配,堆是可以上增长的。

4.4. 数据段--存储全局数据和静态数据。

4.5 代码段--可执行的代码/只读常量。

练习

(1).这里的globalVar是一个全局变量 staticGlobalVar和staticVar是静态变量 他们都是存在C数据段中的   而localVar 和num1都是局部变量 存在栈中选A

 char2本身也是局部变量 而 “abcd”是一个常量 是存在与代码段的 而char2是通过拷贝“abcd”放入栈中的 而char2是数组名 也是首元素地址 *char2所指的位置也是在栈中的

pChar3是局部 所以也是存在于栈中  而pChar3是指针 它是指向代码段中的“abcd”的 所以*pChar3是代码段中的

ptr1是局部 所以也处于栈中 而ptr1指正指向的空间是通过malloc出来的 malloc出来的空间是在堆中的  所以*ptr1在堆中

(2).num1中有十个为int的空间 所以10*4 = 40  char2中除了abcd外还有斜杠0 所以有5个char大小的空间 所以是5*1=5   char2的长度是指abcd所以是4   pChar3是int指针 所以其sizeof大小是4  pChar3指向abcd 所以strlen的长度也是4    ptr1也是int指针 所以sizeof大小也是4()

(1). CCCAA     AAADAB 

(2). 40  5  4  4  4  4  

5.C++内存管理方式

C语言中动态内存管理方式:malloc/calloc/realloc/free

C语言内存管理方式在C++中可以继续使用,但有些地方就无能为力,而且使用起来比较麻烦,因此C++又提 出了自己的内存管理方式:通过new和delete操作符进行动态内存管理

格式:

int main()
{
	int* p1 = new int;
	int* p2 = new int[10];//开10空间

	delete p1;
	delete[] p2;//销毁多空间时使用
	return 0;
}

那么new 和 delete 与 c语言中的 malloc和free 有什么区别?

:除了用法更方便 其他方面是没有区别

这new在创建时 还可以进行初始化

int main()
{
	int* p1 = new int(1);
	int* p2 = new int[10] {1,2,3,4,5,6};//开10空间


	delete p1;
	delete[] p2;//销毁多空间时使用
	return 0;
}

它默认没有初始化 但是用法上面是可以初始化的

上面所讲的都是针对内置类型的

接下来是针对自定义类型

格式:

在调用构造时 会先调用默认构造 有参的会调用有参构造

注意:在申请自定义类型的空间时,new会调用构造函数,delete会调用析构函数,而malloc与free不会。

int main()
{
	A* p1 = new A;
	A* p2 = new A(2);//这里有new修饰 这里不是匿名对象

	delete p1;
	delete p2;
	cout << endl;

	A* p3 = new A[10];
	delete[] p3;

	A* p4 = new A[10]{1,2,3,4,5,6};
	delete[] p4;
	return 0;
}

这里想要开多个空间 是通过p3的写法 开10A类型的对象 也就会调用10次构造函数 delete [] p3也会调用10次析构函数 

对给一次开多个空间的自定义类型 赋初值  采用p4的方式 直接输入之后通过隐式类型转换产生临时变量  然后在拷贝构造给p4 在编译器的优化下 构造+拷贝构造 会直接优化为构造

这是其中一部分调用了多参数构造时的写法

c++采取的扩容全部是手动扩容 即先创建一个更大的空间 再将想要扩容的空间的内容放入新的更大的空间 再将原来的空间销毁掉

6.operator new与operator delete函数

new和delete是用户进行动态内存申请和释放的操作符,operator new 和operator delete是系统提供的 全局函数,new在底层调用operator new全局函数来申请空间,delete在底层通过operator delete全局 函数来释放空间。

通过上述两个全局函数的实现知道,operator new 实际也是通过malloc来申请空间,如果malloc申请空间 成功就直接返回,否则执行用户提供的空间不足应对措施,如果用户提供该措施就继续申请,否则就抛异 常。operator delete 最终是通过free来释放空间的

这里在调用顺序上时 先调用operator new 在调用构造函数 之后是析构函数 最后是 operator delete

也就是说我们的构造和malloc负责的是 不同的空间  析构和free也是不用的空间上作用        

这里就会产生一个问题  为什么非要用operator new与operator delete函数  用malloc和 free 不是更好吗 

malloc失败后会生成空  想要判断是否失败还需要再malloc下面用if进行判断 

而new在创建空间失败后会进行抛异常操作  (这是后面的c++的内容)可以直接进入catch中 

而operator delete 则是为了与operator new进行匹配而且建立的

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值