重载全局的new和delete
::operator new ::operator new[] -> 不可以被声明与同一个namespace
之内
new
会执行三个动作: -> 之前的代码提到:
-
new
本身会开辟内存空间.所以声明方法需要一个size_t size
的参数-
inline void* operator new(size_t size) {}
-
::operator delete ::operator delete[] -> 不可以被声明与同一个namespace
之内
-
delete
本身是归还内存的动作.所以需要接收一根指针-
inline void operator delete(void* ptr) {}
-
上述内容示例代码:
#pragma
#ifndef __NEW_DELETE__
#define __NEW_DELETE__
#include <Windows.h> // 通常来说上面还需要一个宏文件来声明这些不变的系统宏
#include <iostream>
namespace MyDefinition {
void* MyAlloc(size_t size) {
return malloc(size);
}
void MyFree(void* ptr) {
return free(ptr);
}
/* 下面两个操作符重载不能声明在一个namespace当中 -> 因为调用的是全局的 */
void* operator new(size_t size) {
std::cout << "MyAlloc global new() \n";
return MyDefinition::MyAlloc(size);
}
//void* operator new[](size_t size) {
//std::cout << "MyAlloc global new() \n";
//return MyDefinition::MyAlloc(size);
//}
void operator delete(void* ptr) {
std::cout << "MyFree global delete() \n";
return MyDefinition::MyFree(ptr);
}
//void operator delete[](void* ptr) {
//std::cout << "MyFree global delete() \n";
//return MyDefinition::MyFree(ptr);
//}
}
#endif // !__NEW_DELETE__
上述是全局的重载
class
当中的重载
#pragma
#ifndef __CLASS_NEW_DELETE__
#define __CLASS_NEW_DELETE__
#include <iostream>
#include <Windows.h>
class Foo
{
public:
Foo() {}
// ~Foo() { delete(this); } // 这样声明则会删除指针而不是指针指向的对象
void* operator new(size_t);
void operator delete(void*, size_t);
};
inline void* Foo::operator new(size_t size) {
/* 开辟一块内存空间.返回指针 */
return malloc(size);
}
inline void Foo::operator delete(void* ptr, size_t size) {
free(ptr);
}
#endif // !__CLASS_NEW_DELETE__
调用代码:
#include "new_delete_class.hpp"
int main() {
Foo* p = new Foo();
/*
* new这个动作会做三件事
* 1、声明一根指针.调用自己的new(操作符重载)方法开辟一块内存区域
* 2、将自己的方法指针静态转型为指向Foo的指针
* 3、通过指针调用Foo的构造函数
* try {
* void* mem = operator new(sizeof(Foo));
* p = static_cast<Foo*>(mem);
* p->Foo::Foo(); // 通过指针调用Foo的构造函数
* }
* 可以看到现有内存空间才有的类的构造函数调用
*/
delete p;
/*
* 做两件事情
* 1、通过指针去调用Foo类的析构函数
* 2、通过操作符重载释放掉指针空间
* p->~Foo();
* operator delete(p)
*/
}
另一种操作符重载:
#pragma
#ifndef __CLASS_NEW_DELETE__
#define __CLASS_NEW_DELETE__
#include <Windows.h>
class Foo
{
public:
Foo();
void* operator new[](size_t); // 传入数组
void operator delete[](void*, size_t);
};
inline void* Foo::operator new[](size_t size) {
return malloc(size);
}
inline void Foo::operator delete[](void* ptr, size_t size) {
free(ptr);
}
#endif // !__CLASS_NEW_DELETE__
调用代码:
#include "new_delete_class_more.hpp"
int main() {
Foo* f = new Foo[10]; // 调用10次构造函数 -> 也会开辟10块内存空间
delete[10] f; // 调用10次析构函数
}
上述代码可以看到new
这个动作会被分解为三个动作,会回到类当中寻找定义好的代码
强制调用全局的示例代码:
#include "new_delete_class_more.hpp"
int main() {
Foo* fp = ::new Foo;
::delete fp;
/*
* 加了"::"的声明以后会强制调用全局的new和delete
* 如果Foo当中没有定义new和delete也会调用全局的
*/
}
整体类设计示例:
#pragma
#ifndef __CLASS_NEW_DELETE_REAL__
#define __CLASS_NEW_DELETE_REAL__
#include <iostream>
#include <Windows.h>
#include <string>
class Foo
{
public:
Foo(): _id(0) {}
Foo(int i): _id(i) {}
~Foo() {}
/* 新建一个hpp文件创建一块命名空间提供实现 */
static void* operator new(size_t);
static void operator delete(void*, size_t);
static void* operator new[](size_t);
static void operator delete[](void*, size_t);
public:
/* 下面三个成员变量就是类的大小 */
int _id;
long _data;
std::string _str;
};
#endif // !__CLASS_NEW_DELETE_REAL__
注意:
-
上述代码当中调用了很多次的构造函数,那么实际开辟内存区域的时候变量
size_t
的大小会多一个int
类型数据大小 (counter
计数器)-> 该数据的值是调用的构造函数的次数 -
this
指针调用构造函数从counter
近的开始.析构函数从举例counter
远的开始 -> 这里没有画栈空间图所以口语化表达
可以重载全局、可以重载局部、还可以重载new()
-> 注意new
和new()
的区别 -> 并不是构造方法
重载new()
和delete()
-> 不要和构造函数混淆
特点:
-
每一个版本的
new()
的参数列都是独一无二 -
第一个参数固定是
size_t
-> 知道类的大小 -> 如果不是编译会报错 -
其余的参数以
new
指定的placement arguments
为初值
delete()
:
-
也可以重载
-
只有当重载的
new()
调用构造函数抛出异常的时候(new
这个动作被拆解成三步)才会调用这些重载的delete()
-
主要用来归还未能完全创建成功的
object
所占用的memory
示例代码:
#pragma
#ifndef __NEW()_DELETE()__
#define __NEW()_DELETE()__
class Foo
{
public:
Foo();
void* operator new(size_t);
void* operator new(size_t, void* star);
void* operator new(size_t, long extra);
void* operator new(size_t, long extra, char init);
/* 重载对于的delete -> 注意这些重载的delete调用的时机 */
void operator delete(void* star); // 一般的delete -> 对应上面第一个new
void operator delete(void*, void*); // 对应上面第二个 -> 第一个void*参数是默认的delete自带的
void operator delete(void*, long); // 对应上面第三个
void operator delete(void*, long, char); // 对应上面第四个
};
#endif // !__NEW()_DELETE()__
调用字符串的new()
-> 如Foo * p = new(size) Foo
的操作.会返回计数器+size
大小的内容 -> 内存模型,拿到的其实是一根指针
-
这样就实现了悄无声息的多分配一些空间 -> 不仅仅是一根指针大小的空间
-