C++ 編譯器投入大量精力讓 class 與內建型別(primitive types)用法一致。以陣列為例:
A a[100]; // A 是 class
int b[100]; // 內建型別
雖然 a 是使用者定義類別的物件,但使用起來與 int 陣列無異。我們來看語義上的差別。
若 A 為 POD(Plain Old Data),測試顯示 A a[3] 與 A a1, a2, a3 在語義與效能上完全一致,無任何差異。
定義 struct StackObject { int _a, _b; StackObject(): _a(0), _b(1) {} };
在 VC++2010 中,StackObject sa[10]; 會呼叫編譯器產生的 vector constructor iterator,其偽碼如下:
void Vector_constructor_iterator(
int array_size, int array_element_size,
void (*Ctr)(void *addr), char *arrayStartAddress) {
for (int i = 0; i < array_size; ++i) {
void *objAddr = arrayStartAddress + i * array_element_size;
Ctr(objAddr); // 間接呼叫建構函數
}
}
這導致 A a[3] 與逐一定義 A a1, a2, a3 語義發生根本變化:不僅多一次函數呼叫,還需透過函數指標間接呼叫建構函數。測試顯示陣列建構速度下降約 30%,考慮到陣列的應用價值,此代價可接受。
加入 ~StackObject2() { _a = _b = 0; } 後,編譯器產生 eh vector constructor iterator,增加異常處理機制:
int lastCreated = -1;
try {
for (int i = 0; i < array_size; ++i) {
Ctr(objAddr);
lastCreated = i; // 記錄已建構元素
}
} catch (...) {
for (int i = 0; i <= lastCreated; ++i) // 回滾銷毀
Dtr(objAddr);
}
測試顯示帶解構函數的類別陣列建構速度下降近 300%。這再次印證:移除不必要的解構函數至關重要。
C++ built-in array 對 class object 的支援是重要語言構造,體現了 C++ 將類別物件與原始變數同等對待的設計哲學。但開發者必須深入理解其語義與效能影響,才能正確使用。