目前加入了更多的功能,函數擴加至六個:
void free_all_register_address(void); // 釋放
void early_free(void *address); // 手動釋放
void register_address(void *address); // 標記
void deregist_address(void *address); // 註銷
void new_1d(void **ptr, int length, int type_side); // 分配
void re_1d(void **ptr, int length, int type_side) // 重新分配
new_1d()
代替了 malloc()
,re_1d()
代替了 realloc()
,early_free()
代替了 free()
。
而這篇包括主要講述一些瑣碎但重要/有意義的完善,
一些細節優化。
顯然,在 new_1d
以及 re_1d
中,length
和 type_side
輸入的值需要被檢測,
數值不可小於或等於 0 ,所以在函數的前面部分加入:
if( length <= 0 || type_side <= 0){
/*錯誤處理*/
}
具體的錯誤處理,請期待 例外處理系列 。
(如果挑戰/嘗試失敗我會刪除這句,換成日誌輸出)(有構思但未進行實作
在 free_all_register_address
中,釋放地址的次序,
遵從先入先出的模式。(i.e. 遍歷方式:0, 1, 2, 3... index - 1)
個人認為先入後出較具意義。(i.e. 遍歷方式:index - 1, index - 2 ... 0)
例如 創建動態二維陣列,需要以與分配相反的次序釋放。
故此把:
for(int i = 0; i < index; i++){
換成
for(int i = index - 1; i >= 0; i--){
early_free
函數的結構很簡單,
只是 free(address)
+ deregist_address(address)
。
由於函數調用需要消耗一定的時間和空間,
把 early_free
改為巨集函數,可減少一層函數調用,提供微小的效率優化。
#define early_free(address) free(address); deregist_address(address);
可讀性或許下降。
目前 new_1d()
和 re_1d()
的使用方式,
與 malloc()
和 realloc()
比較,有微小的差異。
new_1d()
和 re_1d()
是輸入指標的地址,malloc()
和 realloc()
是輸入指標的值空間。
使用者不需要知道函數內部的細節,使用方法越簡單越好,
我們可以用巨集隱藏起這些細節。
建立巨集函數:
#define new_1d(ptr, length) new_1d(&ptr, length, sizeof(*ptr))
#define re_1d(ptr, length) re_1d(&ptr, length, sizeof(*ptr))
連打 type_side
, sizeof()
的步驟也省去。
注意這個巨集宣告必須放置在 原函數 以及 任何使用到原函數 的 函數 後。
假設 int *ptr = NULL;
已經宣告,
原本是這樣使用的:
new_1d(&ptr, 5, sizeof(int));
現在是這樣使用的:
new_1d(ptr, 5);
是不是簡單多了~
free_all_register_address
:忘記了有使用者調用 free_all_register_address
的可能性,
意味函數有被運行兩次以上的機會,
所以 index 需要重設為零。
這又意味需要的權限不再只是讀取,而是連結。
所以回復為連結的形式,並在最後加入 *index = 0;
。
另一解決方案是用巨集覆蓋函數
#define free_all_register_address() printf("欸欸,不要用這個函數哦。");
注意這個巨集宣告必須放置在 被覆蓋函數 以及 任何使用到該函數 的 函數 後。
令使用者不能調用 free_all_register_address
。
▌然後就完結 垃圾回收器系列 了。