【汇编 C++】在堆中创建对象

28 篇文章 1 订阅

目录

前言

1、我们可以在什么地方创建对象? 

2、malloc与new的区别

        new调用有参构造和无参构造的放式

        小结

3、free与delete的区别 

        什么是析构代理函数? 

        小结 

4、delete与delete[]的区别        

        小结

总结

结语


前言

        本篇文章会涉及到汇编层面的知识,不过没有汇编基础的也可以看,大概知道什么意思就行了,毕竟是来学C++而不是汇编。

        使用到的工具是vs2010

1、我们可以在什么地方创建对象? 

        假设我们有如下类:

#include <stdio.h>
#include <Windows.h>
#include <stdlib.h>

class Person
{
public:
	int x;
	int y;
	Person(){ printf("无参构造。\n"); }
	Person(int x,int y){ printf("有参构造。\n"); }
	~Person(){ printf("析构函数。\n"); }
};

int main()
{

	system("pause");
	return 0;
}

        <1> 全局变量区

        Person P;                                // 在函数的外部定义

        <2> 栈

        void Max() { Person p; }                // 在函数内部定义

        栈区也就是之前汇编调用函数时提升堆栈的'堆栈',只有在函数调用时才会有堆栈,函数调用结束后该堆栈虽然在,但已经被使用并且不属于这个函数。所以说栈(堆栈)中的数据只有函数调用时存在,函数调用完成后将不存在。

        <3> 堆:new delete

        在堆中创建对象:

                C语言:Person* p = (Person*)malloc(sizeof(Person));

                C++:   Person* p = new Person();                // 默认调用无参时,括号可以省略。

        释放对象占用的内存:

                C语言:free(p);

                C++:   delete p;

2、malloc与new的区别

        malloc是C语言提供的用来申请堆区内存的函数,而new是C++中的函数。二者还是有一些区别的,下面将会从汇编的层面去分析区别所在。

        首先是malloc的汇编,如下:

        断点、编译、调试、ALT+8查看汇编:

         可以看到malloc函数就是调用了一个__imp__malloc函数去进行内存申请的(这里就不跟进这个函数内部了,比较乱)。

        然后看new的汇编,如下: 

         查看反汇编:

         可以看到new申请内存的话是比malloc严格一些的,主要有三个步骤:

        申请、检查、调用构造;

        new调用有参构造和无参构造的放式

        new调用无参构造的话可以这样:

        也可以这样:

        new调用有参构造的话传入参数就行了:

        小结

        大概可以总结一下new与malloc了。

        malloc:调用__imp__malloc函数

        new:调用operator new函数、检查是否申请成功、调用类的构造

        如果跟进__imp__malloc与operator new的反汇编的话,其实跟到最后这二者都是调用一个叫做'HeapAlloc'的函数,这是Windows API函数。(可以之间点击链接查看百度百科解释)

        所以:

        如果是给类的对象申请堆区空间的话,new = malloc+检查+构造函数

        在C语言中也有检查堆区是否申请成功的函数

        叫做assert,需要头文件#include <assert.h>

        如下:

3、free与delete的区别 

        直接看汇编:

        free的汇编代码如下:

        没什么特殊的。

        delete:

        可以看到delete是先判断指针是否为空,然后调用析构代理函数,与C语言相比还是比较严格的。

        什么是析构代理函数? 

        单步步入F11跟进函数内部,如下:

        析构代理函数是这样的:

        调用真正的析构、调用delete删除堆区申请的内存。

        小结 

        free:    调用__imp__free函数

        delete:检查内存是否已经释放、调用析构函数、调用operator delete函数

        所以delete = 检查+析构+malloc

4、delete与delete[]的区别        

        我们知道,如果是给类的一个对象申请堆区内存的话,是这样的:

        Person* p = new Person;

        如果是给一个类的对象数组申请堆区空间的话,是这样的:

        Person* p = new Person[10];                        // 申请一个Person p[10]大小的堆区空间

        如下:

        既然是申请数组空间,那么就要用delete[]去释放这个申请的空间。

        我们运行一下看看控制台输出的什么?

         可以看到申请10个Person对象的堆区空间会调用10次构造函数

        释放的时候使用delete[] 也会调用十次析构函数

        那么如果new[]申请,delete释放呢?

        如下:

        会触发中断,可以看到是调用了一次析构函数的,这代表释放了一个Person对象的堆区空间

        一次delete会调用一次析构、释放一次内存

        而delete[]则是调用多次析构、释放整个数组的堆区空间

        那么释放可以循环十次使用delete呢?

        不可以

        因为第一次进入delete的时候就已经触发了中断、程序是不会继续运行下去的。

        小结

        delete一次调用一次析构、释放一次堆区空间

        而delete[]则是调用多次析构、释放整个数组的堆区空间

        new delete 与 new[] delete[]建议配套使用。

        感兴趣的话也可以跟进delete与delete[]的汇编,看是如何实现的,这里我就不跟大家操作了

总结

        1、创建对象可以在全局区、栈中,也可以new申请堆区空间

        2、malloc:调用__imp__malloc函数

              new:    调用operator new函数、检查是否申请成功、调用类的构造

              __imp__malloc与operator new作用大致一样

        3、free:    调用__imp__free函数

             delete: 检查内存是否已经释放、调用析构函数、调用operator delete函数

        4、delete:  调用一次析构、释放一次堆区空间

             delete[]:调用多次析构、释放整个数组的堆区空间

结语

        如果有讲的不好的地方可以私信评论之后会修改;讲错了的地方请指出,谢谢大家!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值