new操作符分析及重载

new与operator new的区别?

可以把new理解为C++中的一个关键字(准确地说是操作符)。
operator new可以当成一个函数名,可能有人会问,函数名怎么可以有空格呢?其实这无伤大雅,想想我们在重载运算符时(+,-等 运算符),函数名的位置不也是类似operator+, operator-吗,+/-符号在重载时也可以作为函数名的一部分。operator new想相当于operator+, operator-的位置。至于到底为什么这里函数名可以有空格,-,+,那是编译器的细节,不多作讨论。
只需要把operator new当成一个函数名就好了。

new的行为分析

这里指的new是指程序中形如: A *a = new A;中的new
关于想要查看new操作符的执行过程,可以查看汇编代码来简要分析,当然也可以直接查看编译器的源码,看是怎么处理的。
下面我们来看一下当使用new创建对象时的过程。
测试代码:
在这里插入图片描述
对应的汇编代码:使用objdump -d a.out查看
在这里插入图片描述
一些参数处理不用关注,只看主要的几条,也就是与代码中new Demo直接相关的:

 a6a:	e8 81 fe ff ff       	callq  8f0 <_Znwm@plt>
 a75:	e8 8e 00 00 00       	callq  b08 <_ZN4DemoC1Ev>

这两句是调用了两个函数,这两个函数的名字(_Znwm, _ZN4DemoC1Ev)是经过name mangling的,可通过如下程序进行转换:

#include <iostream>                                                                                      
#include <cxxabi.h>

using std::cout;
using std::endl;

int main(int argc, char *argv[])
{
    int s;
    cout << argv[0] << " --> ";
    cout << abi::__cxa_demangle(argv[1], NULL, NULL, &s) << endl;

    return 0;
}

上面代码很简单,编译后直接使用,就可查看经过name mangling的标识符对应的原名称。
查看new调用的两个函数:
在这里插入图片描述

可以看到,new操作符其实是调用了两个函数

  1. operator new(unsigned int) ------ 分配内存空间
  2. Demo::Demo() -------- 调用构造函数在上面申请的空间上构建对象

那么new操作符的描述可以如下(不能运行):

new(Type t)
{
	void *buf = operator new(sizoef(Type));  /* 调用operator new来申请内存 */
	char *tmp = (char*)buf;
	Type *ret = new(tmp) Type;                    /* 这句话相当于(Type*(tmp))->Type::Type(), 就是调用构造函数在指定内存构造对象,如果前边的不好理解,就用注释里的理解,但是g++好像不支持直接调用构造函数 */
	return ret;
}

下面是operator new的源码:
在这里插入图片描述
operator new这个函数(全局函数),其实就是包装了一下malloc(处理异常), 这也就是为什么说它是申请内存的了。
执行这儿,只申请了内存,并没有构造对象,所以接下来的工作就是通过一定的方式在指定的内存(申请的 )构造对象。

当我们在程序中执行new A创建对象时,
编译器会把new操作符拆分成上面的两个操作,然后生成相应的汇编指令。
也就是说operator new是new操作符的子操作
注:在执行new A时不一定完全生成两个操作,编译器可能会进行优化。比如:使用默认构造函数时,就没有调用构造函数的步骤,只使用operator new分配的内存。

重载new操作符

虽然说是重载new操作符,但是实际我们只能改变operator new分配空间这一个步骤,至于第二个步骤我们是不能干预的,由编译器来决定。

例子:

在这里插入图片描述
输出结果:
在这里插入图片描述
我们确实改变了operator new(也就是new的第一个步骤)。对应大小为8个字节(编译器计算)
但是上面的例子不能使用delete a; 因为我们在operator new这个步骤没有分配空间。

为什么说可以认为operator new是一个函数呢?

在这里插入图片描述

结果:
在这里插入图片描述
可能看到36, 37, 38行是可以把operator new当函数来调用的。(只不过函数名比较特殊罢了)

使用new创建对象时,如果没有重载operator new, 那么就调用全局的operator new(上图中可以看到,重载的operator new注释了后,调用全局函数operator new(最上方)),如果我们自己没写,也没重载,那么就调用已经定义好的operator new来分配空间。
这个代码在gcc的源码中可以找到。
在这里插入图片描述

同理:
delete也是两个步骤:

  1. 先销毁对象, Type o; o->~Type(); /* 调用析构函数 */
  2. 释放内存:free(o);

总结:

  1. new, delete都是分两个步骤进行的,分配空间/处理对象。
  2. operator new与new的区别,operator new是new的一个子操作,可以当成函数
  3. 我们重载new时,只能重写operator new, 而不能干预构造函数的调用(由编译器处理)

本文对一些概念的理解和解释可能不是很准确。
如果有错误,恳请读者批评指正。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值