2025-08-06
【1】C/C++
00
请注意,本文编写于 59 天前,最后修改于 59 天前,其中某些信息可能已经过时。

当我们使用C++进行项目开发时,总是避免不了使用new来申请空间构建目标对象,但是频繁的申请和释放会导致系统性能的浪费和开销。

当我们设计一个类时,我们应该像以下方式这样设计:

C++
class Airplane { private: struct AirplaneRep { unsigned long miles{ 10 }; // 8 char type{ 'A' }; // 1 16 }; union { AirplaneRep rep{}; // 16 Airplane* next; // 8 }; // 16 public: unsigned long getMiles() { return rep.miles; } char getType() { return rep.type; } void set(unsigned long m, char t) { rep.miles = m; rep.type = t; } static void* operator new(size_t size); static void operator delete(void* ptr); ~Airplane() { std::cout << "Airplane::~Airplane()" << std::endl; } private: static const int BLOCK_SIZE; static Airplane* headOfFreeList; }; Airplane* Airplane::headOfFreeList; const int Airplane::BLOCK_SIZE = 512;

对于new和delete需要我们重新设计和实现:

C++
void* Airplane::operator new(size_t size) { // if (size != sizeof(Airplane)) // { // return ::operator new(size); // } Airplane* p = headOfFreeList; if (p) { headOfFreeList = p->next; } else { Airplane* newBlock = static_cast<Airplane*>(::operator new(BLOCK_SIZE * sizeof(Airplane))); for (int i = 1; i < BLOCK_SIZE - 1; ++i) { newBlock[i].next = &newBlock[i + 1]; } newBlock[BLOCK_SIZE - 1].next = 0; p = newBlock; headOfFreeList = &newBlock[1]; } return p; } void Airplane::operator delete(void* ptr) { if (ptr == 0) { return; } // if (size != sizeof(Airplane)) { // ::operator delete(ptr); // return; // } Airplane* deleteMe = static_cast<Airplane*>(ptr); deleteMe->next = headOfFreeList; headOfFreeList = deleteMe; }

调用时不会有任何不适:

C++
int main() { Airplane* p3 = new Airplane(); std::cout << p3 << std::endl; // p3->set(1000, 'A'); Airplane* p4 = new Airplane(); std::cout << p4 << std::endl; // p4->set(5000, 'A'); Airplane* p5 = new Airplane(); std::cout << p5 << std::endl; delete p3; delete p5; delete p4; free(p3); // std::allocator<int> alloc; // alloc.allocate(10); return 0; }

我们重写了operator new,至于重写的原因,就是因为malloc与free以及new与delete本身的缺陷所导致。

malloc在分配内存时会多分配一点内存至少用来存储具体分配的大小,因此,malloc操作是有代价的,每一次malloc都会浪费一点空间,所以分配空间时malloc的次数越少越好

因此,如上方代码所示我们重写了new。看重写后的new分配空间时的内存分布如下:

当我们第一次调用operator new时,为其在栈上分配栈帧,首先创建Airplane类型的指针p指向headOfFreeListheadOfFreeList是存在静态区的静态变量。这时若p即headOfFreeList为空,我们就调用::operator new一次分配足够多的栈空间,同时创建一个Airplane类型的指针newBlock指向堆空间,并且堆空间内的分区进行连接以便遍历。将newBlock 所指向的0下标的空间的地址 给 p,并将下标为1的空间的地址给headOfFreeList。将p指向的空间给对象

当我们第二次调用operator new时,为其在栈上分配栈帧,首先创建Airplane类型的指针p指向headOfFreeList。p不为空,将p指向的空间给对象。同时使headOfFreeList指向下一部分空间

因此。虽然我们多次调用了operator new,但相较于原本的new会多次浪费资源,重写的new在一定次数的调用中只会浪费一次资源。

这也是一次开辟,多次使用的典型操作。

本文作者:流浪的将军

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!