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

delete this ใน C++: การใช้งานและอันตราย

delete เป็นตัวดำเนินการที่ใช้ปล่อยพื้นที่จัดเก็บของตัวแปร

this pointer เป็นตัวชี้ที่เข้าถึงได้เฉพาะภายใน non-static member function และชี้ไปยังที่อยู่ของออบเจ็กต์ที่เรียก member function นั้น

this pointer เก็บที่อยู่ของออบเจ็กต์ปัจจุบัน อย่างง่ายคือ this pointer ชี้ไปยังออบเจ็กต์ปัจจุบันของคลาส

ทุกครั้งที่เราเรียก member function ผ่านออบเจ็กต์ คอมไพเลอร์จะส่งที่อยู่ของออบเจ็กต์ที่เรียกเป็นพารามิเตอร์แรกใน member function ผ่าน this pointer โดยลับๆ

โดยหลักทั่วไป delete operator ไม่ควรใช้กับ this pointer สมมติถ้าใช้ จะต้องพิจารณาจุดต่อไปนี้

ในทางที่เป็นจริง delete operator ไม่ควรใช้กับ this pointer อย่างไรก็ตาม หากใช้ จะต้องพิจารณาดังนี้:

  • delete operator ทำงานได้เฉพาะกับออบเจ็กต์ที่จัดสรรด้วย operator new (ดูโพสต์นี้) หากออบเจ็กต์ถูกสร้างด้วย new เราสามารถทำ delete this ได้ มิฉะนั้นพฤติกรรมจะไม่ได้รับการกำหนด (undefined behavior)

class A {
public:
    void fun() {
        delete this;
    }
};

int main() {
    /* ต่อไปนี้ถูกต้อง */
    A *ptr = new A;
    ptr->fun();
    ptr = NULL; // ทำให้ ptr เป็น NULL เพื่อให้แน่ใจว่าไม่เข้าถึงผ่าน ptr
    
    /* และต่อไปนี้ไม่ถูกต้อง: Undefined Behavior */
    A a;
    a.fun();
    getchar();
    return 0;
}
  • หลังจาก delete this แล้ว สมาชิกของออบเจ็กต์ที่ถูกลบไม่ควรถูกเข้าถึงหลังการลบ

#include <iostream>
using namespace std;

class A {
    int x;
public:
    A() { x = 0; }
    void fun() {
        delete this;
        /* Invalid: Undefined Behavior */
        cout << x;
    }
};

สิ่งที่ดีที่สุดคือไม่ควรทำ delete this เลย

การลบ this pointer ภายใน member function เป็นสิ่งผิด เราไม่ควรทำ แต่ถ้าทำ สิ่งต่อไปนี้อาจเกิดขึ้น:

  • ถ้าออบเจ็กต์ที่เรียก member function นั้นถูกสร้างบน stack การลบ this pointer จะทำให้แอปพลิเคชัน crash หรือพฤติกรรมไม่ได้รับการกำหนด

  • ถ้าออบเจ็กต์ถูกสร้างบน heap ด้วย new operator การลบ this pointer จะทำลายออบเจ็กต์ จะไม่ crash ทันที แต่หลังจากนั้นถ้า member function พยายามเข้าถึงตัวแปรสมาชิกผ่านออบเจ็กต์นี้ แอปพลิเคชันจะ crash

ตัวอย่าง

#include <iostream>

class Dummy {
    int m_value;
public:
    Dummy(int val) : m_value(val) {}
    void destroy();
    void displayValue();
    void displayText();
};

void Dummy::destroy() {
    delete this;
}

void Dummy::displayValue() {
    std::cout << this->m_value << std::endl;
}

void Dummy::displayText() {
    std::cout << "Not accessing any member function" << std::endl;
}

int main() {
    Dummy * dummyPtr = new Dummy(5);
    dummyPtr->destroy();
    dummyPtr->displayText();
    return 0;
}

เมื่อเราลบ this pointer ใน destroy() member function แล้ว การเรียก displayText() ปลอดภัยเพราะไม่เข้าถึงสมาชิกใดๆ แต่การเรียก displayValue() จะทำให้แอปพลิเคชัน crash เพราะเข้าถึงตัวแปรสมาชิกผ่าน dangling pointer คือ this pointer ที่ถูกลบแล้ว