ソースを参照

feat: 添加 allocator 的使用

liucong5 2 年 前
コミット
aed8ba6e37

+ 4 - 4
cpp/temp-cpp-proj/temp-cpp-proj/src/Airplane.cpp

@@ -96,7 +96,7 @@ void foo_Ariplane() {
 	}
 }
 
-int main() {
-	foo_Ariplane();
-	return 0;
-}
+//int main() {
+//	foo_Ariplane();
+//	return 0;
+//}

+ 91 - 0
cpp/temp-cpp-proj/temp-cpp-proj/src/CustomAllocator.cpp

@@ -0,0 +1,91 @@
+#include <cstddef>
+#include <iostream>
+
+class MyAllocator {
+private:
+	struct obj
+	{
+		struct obj* next;
+	};
+
+public:
+	void* allocate(size_t);
+	void deallocate(void*, size_t);
+
+private:
+	obj* freeStore = nullptr;
+	const int CHUNK = 5;	// 标准库是20
+};
+
+void* MyAllocator::allocate(size_t size)
+{
+	obj* p = nullptr;
+	if (!freeStore) {
+		size_t chunk = CHUNK * size;
+		freeStore = p = (obj*)malloc(chunk);
+
+		if (p == nullptr) {
+			return nullptr;
+		}
+
+		// 连接内存块
+		for (int i = 0; i < CHUNK - 1; ++i) {
+			p->next = (obj*)((char*)p + size);
+			p = p->next;
+		}
+
+		p->next = nullptr; // last
+	}
+	p = freeStore;
+	freeStore = freeStore->next;
+	return p;
+}
+
+void MyAllocator::deallocate(void* p, size_t)
+{
+	// 将 p 收回插入 free list 前端
+	((obj*)p)->next = freeStore;
+	freeStore = (obj*)p;
+}
+
+class Goo {
+public:
+	long L;
+	static MyAllocator myAlloc;
+
+public:
+	Goo(long l) : L(l) {}
+	static void* operator new(size_t size) {
+		return myAlloc.allocate(size);
+	}
+
+	static void operator delete(void* pDead, size_t size) {
+		myAlloc.deallocate(pDead, size);
+	}
+};
+
+MyAllocator Goo::myAlloc;
+
+void foo_myALlocator() {
+	std::cout << sizeof(Goo) << std::endl;
+
+	size_t const N = 4;
+	Goo* p[N];
+
+	for (int i = 0; i < N; ++i) {
+		p[i] = new Goo(i);
+	}
+
+	for (int i = 0; i < 3; ++i) {
+		std::cout << p[i] << std::endl;
+	}
+
+	for (int i = 0; i < N; ++i) {
+		delete p[i];
+	}
+}
+
+int main() {
+	foo_myALlocator();
+	return 0;
+}

+ 1 - 0
cpp/temp-cpp-proj/temp-cpp-proj/temp-cpp-proj.vcxproj

@@ -130,6 +130,7 @@
     <ClCompile Include="src\Airplane.cpp" />
     <ClCompile Include="src\main.cpp" />
     <ClCompile Include="src\Screen.cpp" />
+    <ClCompile Include="src\CustomAllocator.cpp" />
   </ItemGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
   <ImportGroup Label="ExtensionTargets">

+ 3 - 0
cpp/temp-cpp-proj/temp-cpp-proj/temp-cpp-proj.vcxproj.filters

@@ -24,5 +24,8 @@
     <ClCompile Include="src\Airplane.cpp">
       <Filter>源文件</Filter>
     </ClCompile>
+    <ClCompile Include="src\CustomAllocator.cpp">
+      <Filter>源文件</Filter>
+    </ClCompile>
   </ItemGroup>
 </Project>

+ 104 - 0
cpp/内存机制.md

@@ -614,3 +614,107 @@ void Airplane::operator delete(void* p, size_t size)
 
 ![](img/Memory_08.png)
 
+为了实现自己的内存分配,我们给 `Airplane` 和 `Screen` 两个类重写了 `operator new` 和 `operator delete`
+
+**那么如果我有100个类甚至1000个类又该如何?我们不能给每个类都重写** `operator new` **和** `operator delete` **吧?关键是每个类的写法相似,功能相同,所以得想一个办法把自定义内存分配的操作从对象中剥离出来**
+
+所以我们需要一个 `allocator` 分配器对象
+
+```cpp
+#include <cstddef>
+#include <iostream>
+
+class MyAllocator {
+private:
+	struct obj
+	{
+		struct obj* next;
+	};
+
+public:
+	void* allocate(size_t);
+	void deallocate(void*, size_t);
+
+private:
+	obj* freeStore = nullptr;
+	const int CHUNK = 5;	// 标准库是20
+};
+
+void* MyAllocator::allocate(size_t size)
+{
+	obj* p = nullptr;
+	if (!freeStore) {
+		size_t chunk = CHUNK * size;
+		freeStore = p = (obj*)malloc(chunk);
+
+		if (p == nullptr) {
+			return nullptr;
+		}
+
+		// 连接内存块
+		for (int i = 0; i < CHUNK - 1; ++i) {
+			p->next = (obj*)((char*)p + size);
+			p = p->next;
+		}
+
+		p->next = nullptr; // last
+	}
+	p = freeStore;
+	freeStore = freeStore->next;
+	return p;
+}
+
+void MyAllocator::deallocate(void* p, size_t)
+{
+	// 将 p 收回插入 free list 前端
+	((obj*)p)->next = freeStore;
+	freeStore = (obj*)p;
+}
+
+class Goo {
+public:
+	long L;
+	static MyAllocator myAlloc;
+
+public:
+    Goo(long l): L(l) {}
+	static void* operator new(size_t size) {
+		return myAlloc.allocate(size);
+	}
+
+	static void operator delete(void* pDead, size_t size) {
+		myAlloc.deallocate(pDead, size);
+	}
+};
+
+MyAllocator Goo::myAlloc;
+
+void foo_myALlocator() {
+	std::cout << sizeof(Goo) << std::endl;
+
+	size_t const N = 4;
+	Goo* p[N];
+
+	for (int i = 0; i < N; ++i) {
+		p[i] = new Goo(i);
+	}
+
+	for (int i = 0; i < 3; ++i) {
+		std::cout << p[i] << std::endl;
+	}
+
+	for (int i = 0; i < N; ++i) {
+		delete p[i];
+	}
+}
+
+int main() {
+	foo_myALlocator();
+	return 0;
+}
+```
+
+> 上面的代码可能运行不了(与编译器版本有关),但是可以表达我们对 allocator 运行的机制
+
+使用这种写法的 allocator 的内存分配器可以给其他任意类型的对象使用,对象无需再关注内存如何分配,而是仅仅需要引入 `MyAllocator` 并且在 `operator new` 和 `operator delete` 中使用即可
+