跟我学C++中级篇——c++内存分配的管理

一、内存分配和回收

内存的分配回收这是谈了又谈,这里不往外展开,只谈c++默认的new。学习过c++开发的都知道,c++中内存的分配使用new来实现,回收使用delete(数组用delete [])。有的复杂一些的可以使用operator重载new,但如不是特别必要一般是不推荐开发者重载New。另外还有一种方式就是placement new,这个就等于是指定在某个空间上分配对象,有点类似于重新绑定的意思。看过前面的launder那篇的是不是有点发现他们有类似的地方。对,这都是对内存分配后的管理方式。
试着总结一下,在c++中,对内存管理控制的底层方式主要有三类:
1、正常分配回收
使用new 和delete来进行。
2、自定义new
通过重载new操作符来实现
3、受控分配
通过一些具体的限定操作来显示的控制内存分配在栈或者堆空间上。

二、受控分配

在前面的分析中,分析过包括launder和start_lifetime_as这两类内存的管理方式,其实这种内存已经分配出来,不过是又重新包装了一下。这个有点类似于自定义new的行为逻辑,但这两是更高一层的内存处理。有兴趣可以查看以前的文章看一下。
这里重点讲的是对内存的栈和堆的控制。如果说让开发者们说堆和栈有什么不同,可能大多都会讲出几分来,其中肯定有也有讲得头头是道的。但是,如果说让一个对象必须分配在堆上或者栈上,怎么办?答案当然是凉拌。
一般来说,学习c++时,都会接受的知识是:临时变量、函数参数等都在栈中,new分出来的在堆上。但这里还混杂着全局变量和静态局部变量和静态全局全量这两类,还有字符串这个特殊的情况。所以可能开发者一般都不会考虑必须在哪儿。只要知道栈的大小(默认WIN下是1M,LINUX下是10M,当然这个可以调整,不过一般不建议),变量定义时不要超过。堆中分配连续内存的大小注意等等这些就可以了(大家有兴趣可以试试X86和X64不同平台下,一次分配的内存大小和累计分配的内存大小,就会发现爱情不是你相像)。
但有些应用情况就是这么个别,特殊,这么不走寻常路,那你也得会。
1、强制分配在堆上:
强制分配在堆上有两种方式,一种是封装好类,不对外开放只提供接口创建,强制在堆上创建,此种方式不展开,大家一想就明白了。另外一种就是下面的代码:

class ExampleH
{
public:
    ExampleH() = default;
    void Release(){delete this;}

private:
    ~ExampleH() = default;
};

有人会问,为啥把析构函数给private了,应该是构造函数吧?但是仔细分析一下,会发现,对象的创建一定要访问构造函数,否则这和c++的规范就相悖了。也就是如果构造函数私
有化了,那就彻底的只能使用类似第一种的封装方式,给个专门接口创建类了。这样,在栈上创建对象就会引起编译器的报警,提示析构函数被私有化了。
但是类对象创建在哪儿,都得回收内存资源啊。所以需要提供一个显示的接口来析构函数,要记住,为了安全,必须是私有化,而能是保护protected,目的就是为了不管开发者如何
想绕过这个红线,都是不可以的。所以最终就杜绝了在栈上创建对象,只要创建就会报错。
2、强制分配在栈上:

class ExampleS
{
protected:
  //重载new为空,使其无法使用其分配堆内存
  static void *  operator new (std::size_t){};
  static void * operator new [](std::size_t) {};
};

其实道理和在堆上创建类似,使用static的目的是需要其在生命周期内提供创建对象的方法,而protected的目的就是为了在继承中可以使用。

三、问题

这里想到了网上流传的一个某大厂的面试题,如何判断一个内存分配在上堆上还是栈上并判断栈生长的空间?
这个回答可以先确定一种平台类型,比如常见的x86平台,然后利用栈空间生长的方向来确定对象分配在了堆还是栈上,堆是由低到高,栈是由高到低。那么只要创建两个基础局部变量再判断生成的顺序即可。那重点来了,如何没有确定平台下或者虽然在某个平台下但这个栈是自定义的,怎么判断这个栈的生长方向呢:
1、利用调用API函数的参数和其内部局部变量的地址大小来判断,如果参数大,则栈是自低向高生长,反之则自高向低生长。
2、直接查看汇编指令,如果在开始阶段出现类似“sub $32,%esp”之灰的,说明栈是自高向低生长的。
3、查看栈顶寄存器的值,在函数开始和结束时比较二者大小,则可判定。

四、总结

灵活性就意味着难掌握,这是一个必然的结果。就和以前一样,人们的吃食就那么几种,你不吃就饿着。可现在不同啊,自己想吃啥做啥,天南地北的好东西有的是。不想做还可以点外卖,去下馆子,有的是方法不会饿着肚子。但越是如此,人们反而觉得选择上有困难。其实学习亦是如此,c++做一件事,有很多种正常的方式,而且更可怕的是,它还有很多不正常但仍然可以顺利运行的方式。每种方式你换个场景用,可能就崩溃,所以这里就需要开发者更好的掌握这些方式方法后的道理,这才是学习c++的难点所在。
唯其难,所以其门槛也高。门槛高意味着什么不用多说吧。在当下的环境下,c++仍然是一个无法替代的选择的情况下,大家应该知道这是什么意思。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值