Array Decay คือ การที่ Array เลื่อมลดความเป็น Array ไปกลายเป็น Pointer to First Element เมื่อส่งผ่านฟังก์ชันหรือใช้ในบริบทบางอย่าง
ทำไมเกิด Array Decay?
- C/C++ ไม่รองรับ Pass Array by Value (Copy ทั้งอาร์เรย์)
- Array Parameter ใน Function จะถูกปรับเป็น Pointer อัตโนมัติ
void func(int arr[])≡void func(int* arr)≡void func(int* arr, size_t size)
ตัวอย่าง Array Decay
#include <iostream>
using namespace std;
void byValue(int arr[10]) { // จริงๆ เป็น int* arr
cout << "Inside byValue: sizeof(arr) = " << sizeof(arr) << endl; // 8 (pointer size)
}
void byPointer(int* arr) {
cout << "Inside byPointer: sizeof(arr) = " << sizeof(arr) << endl; // 8
}
void byReference(int (&arr)[10]) { // Reference to Array[10]
cout << "Inside byReference: sizeof(arr) = " << sizeof(arr) << endl; // 40
}
int main() {
int arr[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
cout << "In main: sizeof(arr) = " << sizeof(arr) << endl; // 40 (10 * 4)
byValue(arr); // Decay to pointer
byPointer(arr); // Explicit pointer
byReference(arr); // No decay - keeps array type
return 0;
}
ผลลัพธ์
In main: sizeof(arr) = 40 Inside byValue: sizeof(arr) = 8 Inside byPointer: sizeof(arr) = 8 Inside byReference: sizeof(arr) = 40
3 วิธีป้องกัน Array Decay
1. Pass by Reference (แนะนำ)
// Fixed Size
void func(int (&arr)[10]); // เฉพาะ int[10]
void func(int (&arr)[N]); // Template Size
// Template Version (ยืดหยุ่น)
template<size_t N>
void func(int (&arr)[N]) {
cout << "Size: " << N << endl; // รู้ขนาดจริง!
}
// Usage
int a[5] = {1,2,3,4,5};
int b[10] = {1,2,3,4,5,6,7,8,9,10};
func(a); // N=5
func(b); // N=10
2. ใช้ std::array (C++11) - แนะนำมากที่สุด
#include <array>
#include <iostream>
using namespace std;
void func(const array<int, 10>& arr) {
cout << "Size: " << arr.size() << endl; // 10
for (int x : arr) cout << x << " ";
}
int main() {
array<int, 10> arr = {1,2,3,4,5,6,7,8,9,10};
func(arr); // ไม่ Decay, รู้ Size, มี Bounds Checking (at())
}
3. ใช้ std::vector (Dynamic Size)
#include <vector>
#include <iostream>
using namespace std;
void func(const vector<int>& vec) {
cout << "Size: " << vec.size() << endl;
for (int x : vec) cout << x << " ";
}
int main() {
vector<int> vec = {1,2,3,4,5};
func(vec); // ไม่ Decay, Dynamic Size
}
สรุปวิธีส่ง Array เข้า Function
| วิธี | Syntax | Decay? | รู้ Size? | ขนาด Dynamic? | แนะนำ? |
|---|---|---|---|---|---|
| Array Param | void f(int a[]) | ✓ Yes | ✗ No | ✗ No | ✗ |
| Pointer | void f(int* a) | ✓ Yes | ✗ No | ✗ No | ✗ |
| Pointer + Size | void f(int* a, size_t n) | ✓ Yes | Manual | ✓ Yes | △ (C-style) |
| Array Reference | void f(int (&a)[N]) | ✗ No | ✓ Yes (Template) | ✗ Fixed | ✓ (Fixed Size) |
| std::array | void f(const array<T,N>&) | ✗ No | ✓ Yes | ✗ Fixed | ✓✓ Best |
| std::vector | void f(const vector<T>&) | ✗ No | ✓ Yes | ✓ Yes | ✓✓ Best |
| std::span (C++20) | void f(span<T>) | ✗ No | ✓ Yes | ✓ Yes | ✓✓ Modern |
std::span (C++20) - ทันสมัยที่สุด
#include <span>
#include <vector>
#include <array>
#include <iostream>
using namespace std;
void process(span<const int> s) { // Non-owning View
cout << "Size: " << s.size() << endl;
for (int x : s) cout << x << " ";
cout << endl;
}
int main() {
int arr[5] = {1,2,3,4,5};
vector<int> vec = {6,7,8,9,10};
array<int, 5> arr2 = {11,12,13,14,15};
process(arr); // OK: Array → Span
process(vec); // OK: Vector → Span
process(arr2); // OK: Array → Span
process({1,2,3}); // OK: Initializer List → Span
}
Array Decay ในบริบทอื่นๆ
int arr[10];
// 1. Function Parameter (เห็นแล้ว)
void f(int arr[]); // decay
// 2. Assignment (ไม่ได้ - Array ไม่ Assign ได้)
// int b[10] = arr; // ❌ Error
// 3. Conditional Expression
true ? arr : arr; // Decay to int*
// 4. Ternary Operator
int* ptr = condition ? arr : nullptr; // Decay
// 5. Comma Operator
(int*)0, arr; // Decay
// 6. sizeof - ไม่ Decay!
sizeof(arr); // 40 - รู้ขนาดจริง!
// 7. & (Address-of) - ไม่ Decay!
int (*ptrToArr)[10] = &arr; // Type: Pointer to Array[10]
// 8. Range-based for - ไม่ Decay!
for (int x : arr) { } // ใช้ Array Type โดยตรง
// 9. Template Type Deduction
template<typename T> void g(T x);
g(arr); // T = int* (Decay!)
// Template Reference - ไม่ Decay
template<typename T, size_t N> void h(T (&)[N]);
h(arr); // T=int, N=10
สรุป
- Array Decay = Array → Pointer (สูญเสีย Size Info)
- เกิดเมื่อ Pass to Function, ใช้ใน Expression หลายแบบ
- ไม่เกิดกับ: sizeof, & (address-of), Range-based for, Template Reference
- แก้ไขด้วย: std::array (Fixed), std::vector (Dynamic), std::span (C++20 View), Array Reference Template
- Modern C++: ห้ามใช้ Raw Array Parameter ใช้ Container/Span แทน