ภาพรวม
C++ ไม่สามารถ Return Array โดยตรงได้** (Array ไม่มี Copy Assignment) แต่สามารถ Return Pointer to Array หรือใช้ Modern C++ Containers ได้
ปัญหาของ Raw Array Return
// ❌ ผิด: Return Local Array Pointer (Dangling Pointer)
int* badFunc() {
int arr[5] = {1,2,3,4,5};
return arr; // arr ถูกทำลายเมื่อฟังก์ชันจบ!
}
วิธีแก้ไข (เรียงตามความแนะนำ)
1. std::vector (Dynamic Size) - แนะนำสุด
#include <vector>
#include <iostream>
using namespace std;
vector createVector(int n) {
vector vec(n);
for (int i = 0; i < n; i++) vec[i] = i + 1;
return vec; // NRVO/Move: No Copy Overhead (C++11+)
}
int main() {
auto vec = createVector(5);
for (int x : vec) cout << x << " "; // 1 2 3 4 5
}
2. std::array (Fixed Size, Compile-time) - แนะนำ
#include <array>
#include <iostream>
using namespace std;
array createArray() {
array arr;
for (int i = 0; i < 5; i++) arr[i] = i + 1;
return arr; // Return by Value - Copy Elision (C++17 Guaranteed)
}
int main() {
auto arr = createArray();
for (int x : arr) cout << x << " "; // 1 2 3 4 5
}
3. Struct Wrapper (C-Style)
struct ArrayWrapper {
int data[5];
};
ArrayWrapper createWrapped() {
ArrayWrapper w;
for (int i = 0; i < 5; i++) w.data[i] = i + 1;
return w; // Struct มี Copy Assignment ได้
}
4. Dynamic Allocation (new) - Caller Must Delete
int* createDynamicArray(int n) {
int* arr = new int[n];
for (int i = 0; i < n; i++) arr[i] = i + 1;
return arr; // Caller ต้อง delete[]!
}
int main() {
int* arr = createDynamicArray(5);
// ใช้งาน...
delete[] arr; // จำเป็น!
}
5. Static Local Array (Shared State - Limited Use)
int* createStaticArray() {
static int arr[5]; // Persists Across Calls
for (int i = 0; i < 5; i++) arr[i] = i + 1;
return arr;
}
// ⚠️ Shared State, Not Thread-Safe, Fixed Size
6. Output Parameter (Legacy)
void fillArray(int* arr, int size) {
for (int i = 0; i < size; i++) arr[i] = i + 1;
}
int main() {
int arr[5];
fillArray(arr, 5); // Caller Allocates
}
7. C++20: std::span (Non-owning View)
#include <span>
#include <vector>
void process(span data) { // View into Existing Array
for (int& x : data) x *= 2;
}
int main() {
vector vec = {1,2,3,4,5};
process(vec); // Implicit Conversion to Span
}
การเปรียบเทียบ
| วิธี | Size | Ownership | Safety | Performance | แนะนำ |
|---|---|---|---|---|---|
| std::vector | Dynamic | Owner (RAII) | ✅ High | Good (Move/NRVO) | ✅ Best General |
| std::array | Fixed (Compile-time) | Owner (Stack) | ✅ High | Best (No Heap) | ✅ Best Fixed |
| Struct Wrapper | Fixed | Owner (Stack) | ✅ High | Good | ⚠️ Legacy |
| new/delete | Dynamic | Manual | ❌ Low | Good | ❌ Avoid |
| Static Local | Fixed | Shared | ⚠️ Medium | Best | ⚠️ Special Cases |
| Output Param | Any | Caller | Medium | Good | ⚠️ C-Style |
| std::span (C++20) | View | Non-owning | ✅ High | Best | ✅ Modern View |
สรุป Best Practices
- Default:
std::vector(Dynamic) หรือstd::array(Fixed) - Return by Value - ให้ NRVO/Move Semantics ทำงาน (C++11/17)
- ไม่ใช้ Raw Pointer Return** สำหรับ Ownership Transfer
- Output Parameters สำหรับ Performance-Critical Legacy Code
- std::span สำหรับ Non-owning Views (C++20)