Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> C++

วิธี Return Array จากฟังก์ชันใน C++

ภาพรวม

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
}

การเปรียบเทียบ

วิธีSizeOwnershipSafetyPerformanceแนะนำ
std::vectorDynamicOwner (RAII)✅ HighGood (Move/NRVO)✅ Best General
std::arrayFixed (Compile-time)Owner (Stack)✅ HighBest (No Heap)✅ Best Fixed
Struct WrapperFixedOwner (Stack)✅ HighGood⚠️ Legacy
new/deleteDynamicManual❌ LowGood❌ Avoid
Static LocalFixedShared⚠️ MediumBest⚠️ Special Cases
Output ParamAnyCallerMediumGood⚠️ C-Style
std::span (C++20)ViewNon-owning✅ HighBest✅ Modern View

สรุป Best Practices

  1. Default: std::vector (Dynamic) หรือ std::array (Fixed)
  2. Return by Value - ให้ NRVO/Move Semantics ทำงาน (C++11/17)
  3. ไม่ใช้ Raw Pointer Return** สำหรับ Ownership Transfer
  4. Output Parameters สำหรับ Performance-Critical Legacy Code
  5. std::span สำหรับ Non-owning Views (C++20)