代碼對比
// C++
Student student1; // 棧上分配,自動銷毀
Student* student2 = new Student(); // 堆上分配,返回指針,需手動 delete
// C#
Student student = new Student(); // 堆上分配,返回引用 (reference),GC 自動回收
核心區別對照表
| 維度 | C++ `new` | C# `new` |
| 返回類型 | 指針 (`T*`),內存地址 | 引用 (`T` 隱式引用類型),非地址 |
| 內存區域 | 本地堆 (Native Heap / CRT Heap) | 托管堆 (Managed Heap / GC Heap) |
| 生命周期管理 | **手動** `delete` / `delete[]` / 智能指針 | **自動** 垃圾回收 (GC),不可手動釋放 |
| 訪問方式 | 解引用 `->` / `*` | 直接 `.` (語法糖,實為引用解引用) |
| 失敗行為 | 拋 `std::bad_alloc` / 返回 `nullptr` (nothrow) | 拋 `OutOfMemoryException` |
| 數組分配 | `new T[n]` 返回 `T*` | `new T[n]` 返回 `T[]` (數組對象) |
| 定位構造 | 支持 `new (ptr) T()` | 不支持 |
為什麼設計差異巨大?
- 語言哲學:
- C++:**程序員控制一切**,零開銷抽象,手動內存管理極致性能。
- C#:**開發效率優先**,運行時托管 (CLR/GC),內存安全、類型安全、生產力。
- 運行時支持**:
- C++:無運行時 (或極薄 CRT),編譯直出機器碼,`new` 只是調用分配器函數。
- C#:依賴 CLR,`new` 觸發 GC 分配邏輯 (指針碰撞/空閒列表)、寫屏障、代碼生成、對象頭初始化。
- 類型系統**:
- C++:值類型/引用類型由程序員決定 (`T` vs `T*` vs `T&`),模板元編程。
- C#:`class` = 引用類型 (堆)、`struct` = 值類型 (棧/內聯),語言強制區分。
C# 中的「指針」在哪?
- **`unsafe` 上下文**:`fixed`、`stackalloc`、指針類型 `T*`,用於互操作、高性能數值計算。
- **引用傳遞**:`ref`、`out`、`in` 參數,`ref struct` (C# 7.2+),`Span`、`Memory`。
- **句柄**:`GCHandle`、`object` 引用本質是壓縮指針 (Handle),GC 移動對象時更新。
避坑指南
| C++ 習慣 | C# 陷阱 | 正確做法 |
| `delete ptr; ptr = nullptr;` | 無 `delete`,置 null 只斷開引用,GC 不定時回收 | 實現 `IDisposable` 釋放非托管資源,托管內存交給 GC |
| 佈局控制 `#pragma pack` | 類佈局由 CLR 控制 (默認 Auto) | `[StructLayout(LayoutKind.Sequential/Explicit)]` 用於互操作 |
| 拷貝構造/賦值運算符 | 引用賦值只複製引用,非深拷貝 | 實現 `ICloneable` / 複製構造函數 / `record` (C# 9+) |
總結
C++ `new` 給你一把鑰匙 (指針),你負責開門、關門、拆房子。
C# `new` 給你一張入住卡 (引用),前台 (GC) 負責打掃、退房,你只管住。