c++中的new和operator new

文章详细解析了new关键字的执行过程,包括调用operatornew进行内存分配,以及全局重载和类级别重载的区别。还介绍了placementnew用于在特定内存空间初始化对象的情况。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、new关键字

我们通过一段反汇编代码来对于new关键字的执行过程进行解析,源代码如下:

struct A {
  A() { printf("%s\n", __PRETTY_FUNCTION__); }
};

A *test() { return new A(); }

反汇编代码如下:

test():
push   %rbp
mov    %rsp,%rbp
sub    $0x20,%rsp
mov    $0x1,%edi
call   0x401050 <operator new(unsigned long)@plt>
mov    %rax,%rcx
mov    %rax,%rdx
mov    %rax,%rdi
mov    %rcx,-0x18(%rbp)
mov    %rdx,-0x20(%rbp)
call   0x4011f0 <A::A()>
jmp    0x40119d <test()+45>
mov    -0x20(%rbp),%rax
add    $0x20,%rsp
pop    %rbp
ret    

可以看到new关键字可以分为两个阶段:

  • 调用operator new(unsigned long)函数向内存管理系统(ptmolloc)申请内存
  • 调用A::A()对于申请到的内存进行初始化

二、关于operator new

从上文可知,operator new()主要用于进行内存分配,根据影响范围的不同operator new的重载可分为全局重载和类级别的重载

2.1 全局重载

#include <cstdio>
#include <cstdlib>
#include <new>

void *operator new(std::size_t sz) {
  std::printf("1) new(size_t), size = %zu\n", sz);
  if (sz == 0)
    ++sz;

  // avoid std::malloc(0) which may return nullptr on success
  if (void *ptr = std::malloc(sz))
    return ptr;

  throw std::bad_alloc{};
}

void *operator new[](std::size_t sz) {
  std::printf("2) new[](size_t), size = %zu\n", sz);
  if (sz == 0)
    ++sz;

  // avoid std::malloc(0) which may return nullptr on success
  if (void *ptr = std::malloc(sz))
    return ptr;

  throw std::bad_alloc{};
}

void operator delete(void *ptr) noexcept {
  std::printf("3) delete(void*)\n");
  std::free(ptr);
}

void operator delete(void *ptr, std::size_t size) noexcept {
  std::printf("4) delete(void*, size_t)\n");
  std::free(ptr);
}

void operator delete[](void *ptr) noexcept {
  std::printf("5) delete[](void*)\n");
  std::free(ptr);
}

void operator delete[](void *ptr, std::size_t size) noexcept {
  std::printf("6) delete[](void*, size_t)\n");
  std::free(ptr);
}

int main(int argc, char *argv[]) {
  int *p1 = new int;
  delete p1;

  int *p2 = new int[10];
  delete[] p2;
  return 0;
}

2.2 类级别重载

#include <cstddef>
#include <cstdio>

struct X {
  static void *operator new(std::size_t sz) {
    printf("custom new for size=%zu\n", sz);
    return ::operator new(sz);
  }

  static void operator delete(void *ptr, std::size_t sz) {
    printf("custom delete for size=%zu\n", sz);
    ::operator delete(ptr);
  }

  static void *operator new[](std::size_t sz) {
    printf("custom new[] for size=%zu\n", sz);
    return ::operator new(sz);
  }

  static void operator delete[](void *ptr, std::size_t sz) {
    printf("custom delete[] for size=%zu\n", sz);
    ::operator delete[](ptr);
  }
};

int main(int argc, char *argv[]) {
  X *p1 = new X;
  delete p1;

  X *p2 = new X[10];
  delete[] p2;
  return 0;
}

输出

custom new for size=1
custom delete for size=1
custom new[] for size=18
custom delete[] for size=18

三、placement new

一般来说,使用new是从系统的堆中分配空间,然后再对于变量进行初始化。但是某些情况下,需要在特定的内存空间里面进行对象的初始化,这就需要placement操作。

#include <iostream>
using namespace std;

class A {
public:
  A() { cout << "A's constructor" << endl; }

  ~A() { cout << "A's destructor" << endl; }

  void show() { cout << "num:" << num << endl; }

private:
  int num;
};

int main() {
  char mem[100];
  mem[0] = 'A';
  mem[1] = '\0';
  mem[2] = '\0';
  mem[3] = '\0';
  cout << (void *)mem << endl;
  A *p = new (mem) A;
  cout << p << endl;
  p->show();
  p->~A();
}

输出:

0x7fff42f01e80
A's constructor
0x7fff42f01e80
num:65
A's destructor

参考

  1. cppreference
  2. overloading-new-delete-operator-c
  3. placement new
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值