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 Delete | Crash / Corruption | Set ptr = nullptr หลัง delete |
| Use After Delete | Dangling Pointer / UB | Set ptr = nullptr |
| Memory Leak | RAM เต็ม漸漸 | ทุก new ต้องมี delete คู่ |
| Mismatch new/delete | UB | new[] ↔ 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 แทน