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

การเรียก Class Method ผ่าน NULL Class Pointer ใน C++

ภาพรวม

คล้ายกับบทความก่อนหน้า การเรียก Member Function ผ่าน NULL Class Pointer ใน C++ เป็น Undefined Behavior (UB) แม้จะ "ทำงานได้" บนบาง Compiler แต่เป็นการเขียนโค้ดที่ผิดและอันตราย

ตัวอย่างโค้ด (แสดงพฤติกรรม - ไม่แนะนำ)

#include <iostream>
using namespace std;

class Example {
public:
    void func() {
        cout << "The function is called through Null class pointer.";
    }
};

int main() {
    Example* p = nullptr;
    p->func();  // Undefined Behavior!
    return 0;
}

ผลลัพธ์ (บนบาง Compiler)

The function is called through Null class pointer.

ทำไมถึงเป็น Undefined Behavior?

  1. C++ Standard ([expr.call]): "If the object expression is a null pointer, the behavior is undefined"
  2. Non-virtual Functions: Compile เป็นฟังก์ชันทั่วไปรับ this pointer → ถ้าไม่ใช้ this อาจรันได้
  3. Virtual Functions: ต้องอ่าน VTable ผ่าน this → Crash ทันที
  4. Data Member Access: Dereference Null Pointer → Crash

ตัวอย่างที่ Crash แน่นอน


class WillCrash {
    int data = 42;
public:
    void accessData() { cout << data; }  // Crash: this->data
    virtual void virtualMethod() {}      // Crash: vtable lookup
};

int main() {
    WillCrash* p = nullptr;
    p->accessData();      // Crash
    p->virtualMethod();   // Crash
}

การป้องกันและ Best Practices

1. ตรวจสอบ Null Pointer เสมอ


if (ptr != nullptr) {
    ptr->func();
}

2. ใช้ References แทน Pointers (เมื่อไม่ต้องการ Null)


void safeCall(Example& obj) {  // Reference ไม่เป็น Null ได้
    obj.func();
}

3. ใช้ Smart Pointers


auto ptr = make_unique();
if (ptr) ptr->func();  // Safe
// หรือ
ptr->func();  // Safe ถ้า ensure ไม่เป็น null

4. Contract/Assertions (Debug Build)


#include 
assert(ptr != nullptr);
ptr->func();

5. C++20 Contracts (Proposed)


[[pre: ptr != nullptr]] ptr->func();

Static Analysis Tools

  • Clang-Tidy: bugprone-null-dereference
  • Cppcheck: Null Pointer Dereference
  • PVS-Studio: V522, V595, V757
  • Compiler Warnings: -Wnull-dereference (GCC/Clang)

สรุป

สถานการณ์พฤติกรรมมาตรฐาน
Non-virtual, No Data Accessอาจ "ทำงานได้"UB
Access Data MemberCrash (Segfault)UB
Virtual Function CallCrash (Segfault)UB
Dynamic Cast / typeidCrash/UBUB

ข้อสรุป: ห้ามเรียก Member Function ผ่าน Null Pointer เด็ดขาด ใช้ References, Smart Pointers, หรือ Null Checks แทน