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

Operator new และ delete ใน C++ (จัดการหน่วยความจำ Dynamic)

new และ delete เป็น Operators ใน C++ สำหรับ Dynamic Memory Allocation บน Heap (Free Store)

new Operator - จองหน่วยความจำ

Single Object


// Syntax
Type* ptr = new Type;           // Uninitialized
Type* ptr = new Type();         // Value-initialized (0/null)
Type* ptr = new Type(value);    // Initialized with value
Type* ptr = new Type{value};    // Uniform initialization (C++11)

Array


Type* ptr = new Type[size];        // Default initialize
Type* ptr = new Type[size]();      // Value initialize (0)
Type* ptr = new Type[size]{1,2,3}; // List initialize (C++11)

Placement New (Advanced)


char buffer[sizeof(MyClass)];
MyClass* obj = new (buffer) MyClass();  // Construct at specific address
obj->~MyClass();  // Manual destructor call

delete Operator - ปล่อยหน่วยความจำ


// Single Object
delete ptr;

// Array (ต้องใช้ [] เสมอ!)
delete[] ptr;

// Placement Delete (pair กับ Placement New)
operator delete(ptr, buffer);

โค้ดตัวอย่างครบถ้วน

#include <iostream>
#include <new>      // for std::nothrow, std::bad_alloc
using namespace std;

class MyClass {
    int id;
public:
    MyClass(int i = 0) : id(i) { cout << "Constructor " << id << endl; }
    ~MyClass() { cout << "Destructor " << id << endl; }
    void show() { cout << "ID: " << id << endl; }
};

int main() {
    // 1. Single Object
    cout << "=== Single Object ===" << endl;
    MyClass* p1 = new MyClass(1);
    p1->show();
    delete p1;
    
    // 2. Array
    cout << "\n=== Array ===" << endl;
    MyClass* arr = new MyClass[3];  // เรียก Constructor 3 ครั้ง
    // arr[0], arr[1], arr[2]...
    delete[] arr;  // เรียก Destructor 3 ครั้ง - สำคัญมาก!
    
    // 3. NotThrow Version (ไม่ทิ้ง Exception)
    cout << "\n=== No-throw new ===" << endl;
    MyClass* p2 = new (nothrow) MyClass(2);
    if (!p2) {
        cout << "Allocation failed!" << endl;
    } else {
        delete p2;
    }
    
    // 4. Primitive Types
    cout << "\n=== Primitive Types ===" << endl;
    int* pi = new int(42);
    double* pd = new double[10];
    pd[0] = 3.14;
    cout << *pi << ", " << pd[0] << endl;
    delete pi;
    delete[] pd;
    
    // 5. Exception Safety
    cout << "\n=== Exception Safety ===" << endl;
    try {
        // 配置หน่วยความจำขนาดใหญ่
        int* big = new int[1000000000];  // อาจ throw bad_alloc
        delete[] big;
    } catch (const bad_alloc& e) {
        cout << "Out of memory: " << e.what() << endl;
    }
    
    return 0;
}

ผลลัพธ์ตัวอย่าง

=== Single Object ===
Constructor 1
ID: 1
Destructor 1

=== Array ===
Constructor 0
Constructor 0
Constructor 0
Destructor 0
Destructor 0
Destructor 0

=== No-throw new ===
Constructor 2
Destructor 2

=== Primitive Types ===
42, 3.14

=== Exception Safety ===
Out of memory: std::bad_alloc

ข้อผิดพลาดทั่วไป (Common Mistakes)

ข้อผิดพลาด ผลลัพธ์ แก้ไข
delete arr; (Array)Undefined Behavior (มักเรียก Destructor แค่ตัวแรก)ใช้ delete[] arr;
delete[] ptr; (Single)Undefined Behaviorใช้ delete ptr;
Double DeleteCrash / CorruptionSet ptr = nullptr หลัง delete
Use After DeleteDangling Pointer / UBSet ptr = nullptr
Memory LeakRAM เต็ม漸漸ทุก new ต้องมี delete คู่
Mismatch new/deleteUBnew[] ↔ delete[], new ↔ delete

Modern C++: หลีกเลี่ยง Raw new/delete


#include <memory>
#include <vector>
#include <string>

// ✓ Smart Pointers (Auto Management)
unique_ptr<MyClass> p1 = make_unique<MyClass>(1);
shared_ptr<MyClass> p2 = make_shared<MyClass>(2);

// ✓ Containers (Auto Management)
vector<MyClass> vec;
vec.emplace_back(3);
vector<int> arr(100);  // แทน new int[100]

// ✓ String (Auto Management)
string s = "Hello";  // แทน char* + new/delete

เมื่อไหร่ต้องใช้ new/delete โดยตรง?

  • เขียน Custom Allocator / Memory Pool
  • Interfacing กับ C API / Legacy Code
  • Placement New สำหรับ Object Pool / Embedded Systems
  • Low-level Systems Programming
  • Performance-critical code ที่ Profile แล้วพบว่า Smart Pointer ช้า

RAII (Resource Acquisition Is Initialization)

หลักการ: Resource ผูกกับ Object Lifetime


// RAII Wrapper สำหรับ Raw Pointer
template<typename T>
class ScopedPtr {
    T* ptr;
public:
    explicit ScopedPtr(T* p = nullptr) : ptr(p) {}
    ~ScopedPtr() { delete ptr; }
    
    // Non-copyable
    ScopedPtr(const ScopedPtr&) = delete;
    ScopedPtr& operator=(const ScopedPtr&) = delete;
    
    // Movable
    ScopedPtr(ScopedPtr&& other) noexcept : ptr(other.ptr) { other.ptr = nullptr; }
    ScopedPtr& operator=(ScopedPtr&& other) noexcept {
        if (this != &other) { delete ptr; ptr = other.ptr; other.ptr = nullptr; }
        return *this;
    }
    
    T& operator*() const { return *ptr; }
    T* operator->() const { return ptr; }
    T* get() const { return ptr; }
};

แต่ในทางปฏิบัติ ใช้ std::unique_ptr แทน