auto layer = new AccelerometerTest();
addChild(layer);
layer->release(); // 為什麼要 release?
Cocos2d-x 物件繼承 Ref,採用**手動引用計數** (類似 COM/Objective-C MRC)。
new:分配記憶體,**引用計數 = 1** (你擁有它)。addChild(node):父節點會呼叫 node->retain(),**引用計數 +1 = 2** (父節點也擁有它)。release():引用計數 -1。歸 0 時自動 delete this。layer->release()?平衡 new 帶來的初始擁有權。
new 了 → 你負責釋放 (計數 1)。addChild 讓父節點也擁有它 (計數 2)。release() → 計數變 1 (僅父節點擁有)。removeChild → release() → 計數歸 0 → 記憶體釋放。**完美無洩漏。**release() 會怎樣?release() → 計數變 1 ≠ 0。create() (自動 autorelease)// 標準 Cocos2d-x 節點類都有這個靜態方法
auto layer = AccelerometerTest::create(); // 內部:new -> init() -> autorelease() -> return
// autorelease() 將物件放入「自動釋放池」,當前幀結束時自動 release() 一次。
addChild(layer); // retain() -> 計數 1 (父節點擁有)
// **此處絕對不能再手動 release()!** 因為你沒有初始擁有權 (已被 autorelease 標記)。
// 父節點移除時 release() -> 計數 0 -> 釋放。正確。
| 寫法 | 創建 | addChild 後計數 | 需手動 release? | 適用場景 |
|---|---|---|---|---|
new Class() | 計數 1 (你擁有) | 2 | 是 (平衡 new) | 需立即控制生命週期、非節點類、舊代碼維護 |
Class::create() | 計數 1 + autorelease 標記 | 1 (父節點擁有) | 否 (會過度釋放崩潰) | **現代標準推薦**,所有繼承 Ref 的節點類 |
autorelease() 原理// 簡化版實現
Ref* Ref::autorelease() {
PoolManager::getInstance()->getCurrentPool()->addObject(this);
return this;
}
// 每幀結束 Director::mainLoop -> PoolManager::getCurrentPool()->clear()
// -> 遍歷池內物件呼叫 release()。
**注意**:autorelease 不是「立即釋放」,而是「延遲到幀結束釋放」。這保證了 create() 返回的物件在當前函數棧幀內安全可用,且若隨即 addChild 被 retain,則自動釋放池的 release 只是抵消 create 內部的隱性擁有權,不影響父節點的擁有權。
代碼中 new ...; addChild; release(); 是**正確的手動管理模式** (平衡 new 的擁有權)。
**現代開發請直接用 Class::create() 並省略 release()**,讓自動放池和父子關係自動管理生命週期,更安全、更簡潔、更符合框架設計意圖。