需要動態管理大量對象時,常見兩種模式:
Class* p = new Class[N]; - 連續內存塊,每個元素是對象本身。Class* arr[N]; 或 Class** arr = new Class*[N]; - 連續指針數組,每個指針指向獨立 new 出的對象。#include <iostream>
using namespace std;
class Student {
int score;
public:
void set(int x) { score = x + 6; }
int get() { return score * score; }
};
int main() {
const int N = 5;
// === 方式1:堆上對象數組 ===
cout << "=== 堆上對象數組 ===" << endl;
Student* p = new Student[N]; // 分配連續 5 個 Student 對象
Student* p0 = p; // 保存首地址用於釋放
for (int i=0; iset(i);
cout << "p[" << i << "]: " << p->get() << endl;
++p; // 指針算術移動到下一個對象
}
delete[] p0; // 必須用首地址釋放!
// delete[] p; // 錯誤!p 已移動,非首地址
// === 方式2:對象指針數組 ===
cout << "\n=== 對象指針數組 ===" << endl;
Student* p1[N]; // 棧上指針數組 (N為常量)
// 或 Student** p1 = new Student*[N]; // 堆上指針數組
for (int i=0; iset(i+1);
cout << "p1[" << i << "]: " << p1[i]->get() << endl;
delete p1[i]; // 單獨刪除每個對象
}
// 若 p1 在堆上:delete[] p1; // 只刪指針數組,不刪對象
return 0;
}
| 維度 | 堆上對象數組 (new T[N]) | 對象指針數組 (T* arr[N]) |
|---|---|---|
| 內存佈局 | 連續塊,對象緊密排列 | 指針連續,對象分散在堆各處 |
| 分配次數 | 1 次 new[] | N+1 次 (1次指針數組 + N次對象) |
| 釋放方式 | 1 次 delete[] 首指針 | N 次 delete 對象 + 1次 delete[] 指針數組 |
| 緩存友好性 | 極佳 (空間局部性) | 差 (指針追蹤導致缓存未命中) |
| 對象大小固定 | 是 | 可異構 (指向派生類對象) |
| 多態支持 | 否 (對象切片) | 是 (基類指針指向派生對象) |
| 擴容/插入/刪除 | 困難 (需重新分配拷貝) | 靈活 (操作指針即可) |
| 內存碎片 | 無 | 易產生 |
Student* p = new Student[N];
for (int i=0; i
Student* arr[100]; // 棧上數組,值未初始化 (野指針)
arr[0]->set(1); // 崩潰!
// 正確:初始化為 nullptr
Student* arr[100] = {nullptr};
// 或 vector vec(100, nullptr);
// 1. 同類對象集合:vector (連續、自動管理、可擴容)
vector students(N);
students[0].set(1);
// 2. 多態集合:vector> (智能指針、自動釋放、無洩漏)
vector> polys;
polys.push_back(make_unique());
polys.push_back(make_unique());
// 3. 共享所有權:vector>
// 4. 固定大小高性能:array (棧上/成員內連續存儲)
vector<T> / new T[N] (堆上對象數組)vector<unique_ptr<Base>> (對象指針數組現代化)理解底層內存模型差異,能幫助你在性能、靈活性、安全性之間做出正確架構決策。