一、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