อนุญาตให้ลบหรือไม่


232

มันอนุญาตให้delete this;หากคำสั่งลบเป็นคำสั่งสุดท้ายที่จะดำเนินการในอินสแตนซ์ของชั้นเรียนที่? แน่นอนฉันแน่ใจว่าวัตถุที่แสดงโดยthis-pointer นั้นnewถูกสร้างขึ้นอย่างสมบูรณ์

ฉันกำลังคิดเกี่ยวกับสิ่งนี้:

void SomeModule::doStuff()
{
    // in the controller, "this" object of SomeModule is the "current module"
    // now, if I want to switch over to a new Module, eg:

    controller->setWorkingModule(new OtherModule());

    // since the new "OtherModule" object will take the lead, 
    // I want to get rid of this "SomeModule" object:

    delete this;
}

ฉันจะทำสิ่งนี้ได้ไหม


13
ปัญหาหลักคือถ้าคุณdelete thisคุณสร้างข้อต่อแน่นระหว่างคลาสและวิธีการจัดสรรที่ใช้สำหรับสร้างวัตถุของคลาสนั้น นั่นคือการออกแบบ OO ที่แย่มากเนื่องจากสิ่งพื้นฐานที่สุดใน OOP คือการสร้างคลาสของตนเองซึ่งไม่ทราบหรือสนใจว่าผู้โทรทำอะไร ดังนั้นคลาสที่ออกแบบมาอย่างเหมาะสมไม่ควรรู้หรือสนใจว่ามันถูกจัดสรรอย่างไร หากคุณมีเหตุผลบางอย่างที่ต้องการกลไกแปลกประหลาดฉันคิดว่าการออกแบบที่ดีกว่าคือการใช้คลาส wrapper รอบคลาสจริงและปล่อยให้ wrapper จัดการกับการจัดสรร
Lundin

คุณลบsetWorkingModuleไม่ได้เหรอ?
Jimmy T.

คำตอบ:


238

C ++ FAQ Lite มีรายการเฉพาะสำหรับสิ่งนี้

ฉันคิดว่าคำพูดนี้สรุปได้อย่างดี

ตราบใดที่คุณระมัดระวังมันก็โอเคสำหรับวัตถุที่จะฆ่าตัวตาย (ลบสิ่งนี้)


15
FQA ที่เกี่ยวข้องยังมีความคิดเห็นที่เป็นประโยชน์: yosefk.com/c++fqa/heap.html#fqa-16.15
Alexandre C.

1
เพื่อความปลอดภัยคุณสามารถใช้ destructor ส่วนตัวบนวัตถุดั้งเดิมเพื่อให้แน่ใจว่ามันไม่ได้ถูกสร้างขึ้นบนสแต็กหรือเป็นส่วนหนึ่งของอาร์เรย์หรือเวกเตอร์
Cem Kalyoncu

กำหนด 'ระวัง'
CinCout

3
'ระวัง' ถูกกำหนดไว้ในบทความคำถามที่พบบ่อยที่เชื่อมโยง (ในขณะที่ลิงค์ FQA ส่วนใหญ่พูดจาโผงผาง - เหมือนเกือบทุกอย่างในนั้น - C ++ แย่แค่ไหน)
CharonX

88

ใช่delete this;ได้กำหนดผลลัพธ์ตราบเท่าที่ (ตามที่คุณระบุไว้) คุณมั่นใจได้ว่าวัตถุได้รับการจัดสรรแบบไดนามิกและ (แน่นอน) ไม่เคยพยายามใช้วัตถุหลังจากที่มันถูกทำลาย ในช่วงหลายปีที่ผ่านมามีคำถามมากมายเกี่ยวกับสิ่งที่มาตรฐานพูดถึงโดยเฉพาะdelete this;เมื่อเทียบกับการลบตัวชี้อื่น ๆ คำตอบนั้นค่อนข้างสั้นและง่าย: มันไม่ได้พูดอะไรมาก มันเพิ่งบอกว่าdeleteตัวถูกดำเนินการจะต้องเป็นนิพจน์ที่กำหนดตัวชี้ไปยังวัตถุหรืออาร์เรย์ของวัตถุ มันจะพูดถึงรายละเอียดเล็กน้อยเกี่ยวกับสิ่งต่าง ๆ เช่นวิธีการคำนวณฟังก์ชันการจัดสรรคืน (ถ้ามี) เพื่อเรียกหน่วยความจำ แต่ส่วนทั้งหมดdelete (§ [expr.delete]) ไม่ได้กล่าวถึงdelete this;โดยเฉพาะเลย ส่วนที่เกี่ยวกับผู้ทำลายไม่พูดถึงdelete this ในที่เดียว (§ [class.dtor] / 13):

ณ จุดนิยามของ destructor เสมือน (รวมถึงคำจำกัดความโดยนัย (15.8)) ฟังก์ชันการจัดสรรคืนที่ไม่ใช่อาเรย์จะถูกพิจารณาราวกับว่าสำหรับนิพจน์ลบสิ่งนี้ปรากฏในตัวทำลายแบบไม่เสมือนของคลาส destructor (ดู 8.3.5 )

สิ่งนี้มีแนวโน้มที่จะสนับสนุนแนวคิดที่ว่ามาตรฐานนั้นdelete this;มีความถูกต้อง - หากมันไม่ถูกต้องประเภทของมันจะไม่มีความหมาย นั่นเป็นที่เดียวที่มาตรฐานกล่าวถึงdelete this;เท่าที่ฉันรู้

อย่างไรก็ตามบางคนคิดว่าdelete thisแฮ็คที่น่ารังเกียจและบอกใครก็ตามที่จะฟังว่าควรหลีกเลี่ยง ปัญหาที่อ้างถึงอย่างหนึ่งคือความยากลำบากในการรับรองว่าวัตถุของคลาสจะถูกจัดสรรแบบไดนามิกเท่านั้น คนอื่นคิดว่ามันเป็นสำนวนที่สมเหตุสมผลอย่างสมบูรณ์แบบและใช้มันตลอดเวลา โดยส่วนตัวแล้วฉันอยู่ตรงกลาง: ฉันไม่ค่อยได้ใช้มัน แต่อย่าลังเลที่จะทำเช่นนั้นเมื่อมันดูเหมือนจะเป็นเครื่องมือที่เหมาะสมสำหรับงาน

เวลาหลักที่คุณใช้เทคนิคนี้คือกับวัตถุที่มีชีวิตที่เกือบทั้งหมดของมันเอง ตัวอย่างหนึ่งที่ James Kanze อ้างถึงคือระบบเรียกเก็บเงิน / การติดตามที่เขาทำงานให้กับ บริษัท โทรศัพท์ เมื่อคุณเริ่มโทรหาบางสิ่งจะรับทราบและสร้างphone_callวัตถุ จากจุดนั้นเป็นต้นไปphone_callวัตถุจะจัดการกับรายละเอียดของการโทร (ทำการเชื่อมต่อเมื่อคุณหมุนเพิ่มรายการลงในฐานข้อมูลเพื่อบอกว่าเมื่อการโทรเริ่มขึ้นอาจเชื่อมต่อผู้คนมากขึ้นถ้าคุณทำการประชุมทางโทรศัพท์ ฯลฯ ) เมื่อ คนสุดท้ายที่วางสายphone_callวัตถุทำหน้าที่เก็บหนังสือเล่มสุดท้าย (เช่นเพิ่มรายการในฐานข้อมูลเพื่อบอกว่าเมื่อคุณวางสายเพื่อให้พวกเขาสามารถคำนวณระยะเวลาที่คุณโทร) และทำลายตัวเอง อายุการใช้งานของphone_callวัตถุขึ้นอยู่กับว่าคนแรกที่เริ่มต้นการโทรและเมื่อคนสุดท้ายที่ออกจากการโทร - จากมุมมองของส่วนที่เหลือของระบบมันเป็นพื้นโดยพลการทั้งหมดดังนั้นคุณจึงไม่สามารถ ผูกไว้กับขอบเขตศัพท์ใด ๆ ในรหัสหรืออะไรก็ได้ในการสั่งซื้อ

สำหรับใครก็ตามที่สนใจว่าการเข้ารหัสประเภทนี้สามารถเชื่อถือได้อย่างไร: ถ้าคุณโทรออกจากหรือผ่านเกือบทุกส่วนของยุโรปมีโอกาสที่ค่อนข้างดีที่มีการจัดการ (อย่างน้อยก็ส่วนหนึ่ง) ด้วยรหัส นั่นทำสิ่งนี้


2
ขอบคุณฉันจะใส่ไว้ในความทรงจำของฉัน ฉันคิดว่าคุณกำหนด constructors และ destructors เป็นส่วนตัวและใช้วิธีคงที่จากโรงงานเพื่อสร้างวัตถุดังกล่าว
Alexandre C.

@Alexandre: คุณอาจจะทำอย่างนั้นในกรณีส่วนใหญ่แล้ว - ฉันไม่รู้ว่าจะอยู่ใกล้กับรายละเอียดทั้งหมดของระบบที่เขาทำงานอยู่ดังนั้นฉันจึงไม่สามารถพูดได้อย่างแน่นอน
Jerry Coffin

วิธีที่ฉันมักจะแก้ไขปัญหาของวิธีการจัดสรรหน่วยความจำคือการรวมbool selfDeleteพารามิเตอร์ในตัวสร้างที่ได้รับมอบหมายให้กับตัวแปรสมาชิก จริงอยู่ที่ว่านี่หมายถึงการมอบเชือกให้โปรแกรมเมอร์เพียงพอที่จะผูกบ่วงไว้ในนั้น แต่ฉันพบว่าการรั่วไหลของหน่วยความจำดีกว่า
MBraedley

1
@ MBraedley: ฉันทำแบบเดียวกัน แต่ชอบที่จะหลีกเลี่ยงสิ่งที่ดูเหมือนว่าฉันจะเป็นกระบอง
Jerry Coffin

สำหรับใครที่อาจสนใจ ... มีโอกาสที่ดีงามที่มันถูกจัดการ (อย่างน้อยในบางส่วน) thisตามรหัสที่ไม่ตรง thisใช่รหัสจะถูกจัดการโดยตรง ;)
Galaxy

46

ถ้ามันทำให้คุณกลัวมีแฮ็กที่ถูกกฎหมายอย่างสมบูรณ์:

void myclass::delete_me()
{
    std::unique_ptr<myclass> bye_bye(this);
}

ฉันคิดว่าdelete thisมันเป็นสำนวน C ++ แต่และฉันนำเสนอสิ่งนี้เป็นความอยากรู้

มีกรณีที่โครงสร้างนี้มีประโยชน์จริง ๆ - คุณสามารถลบวัตถุหลังจากโยนข้อยกเว้นที่ต้องการข้อมูลสมาชิกจากวัตถุ วัตถุยังคงใช้ได้จนกว่าจะเกิดการโยน

void myclass::throw_error()
{
    std::unique_ptr<myclass> bye_bye(this);
    throw std::runtime_exception(this->error_msg);
}

หมายเหตุ: หากคุณใช้คอมไพเลอร์ที่เก่ากว่า C ++ 11 คุณสามารถใช้std::auto_ptrแทนstd::unique_ptrได้มันจะทำแบบเดียวกัน


ฉันไม่สามารถคอมไพล์ไฟล์นี้ได้โดยใช้ c ++ 11 มีตัวเลือกคอมไพเลอร์พิเศษไหม? นอกจากนี้ยังไม่จำเป็นต้องย้ายตัวชี้นี้หรือไม่?
นกฮูก

@Owl ไม่แน่ใจว่าสิ่งที่คุณหมายถึงการทำงานสำหรับฉัน: ideone.com/aavQUK การสร้างunique_ptrจากอีกอัน unique_ptrต้องย้าย แต่ไม่ใช่จากตัวชี้แบบดิบ หากไม่มีการเปลี่ยนแปลงใน C ++ 17
Mark Ransom

Ahh C ++ 14 นั่นเป็นเหตุผล ฉันต้องอัปเดต c ++ ของฉันในกล่อง dev ของฉัน ฉันจะลองอีกครั้งในคืนนี้กับระบบ gentoo ที่เพิ่งเกิดใหม่ของฉัน!
Owl

25

หนึ่งในเหตุผลที่ C ++ ได้รับการออกแบบมาเพื่อให้ง่ายต่อการนำรหัสมาใช้ซ้ำ โดยทั่วไปควรเขียน C ++ เพื่อให้ทำงานได้ว่าคลาสนั้นถูกสร้างอินสแตนซ์บนฮีปในอาร์เรย์หรือบนสแต็ก "Delete this" เป็นการฝึกการเขียนโค้ดที่แย่มากเพราะมันจะใช้ได้ก็ต่อเมื่อมีการกำหนดอินสแตนซ์เดียวบนฮีป และไม่ควรมีคำสั่งลบอื่น ๆ ซึ่งโดยทั่วไปแล้วนักพัฒนาส่วนใหญ่จะใช้ล้างข้อมูลฮีป การทำเช่นนี้จะถือว่าไม่มีโปรแกรมเมอร์บำรุงรักษาในอนาคตที่จะรักษาหน่วยความจำรั่วไหลโดยการเพิ่มคำสั่งลบ

แม้ว่าคุณจะรู้ล่วงหน้าว่าแผนปัจจุบันของคุณคือการจัดสรรอินสแตนซ์เดียวบนฮีปแล้วจะเกิดอะไรขึ้นหากนักพัฒนาแฮปปี้โกโกโชคดีเข้ามาในอนาคตและตัดสินใจที่จะสร้างอินสแตนซ์บนสแต็ก หรือถ้าเขาตัดและวางบางส่วนของคลาสเป็นคลาสใหม่ที่เขาตั้งใจจะใช้กับสแต็ก เมื่อรหัสมาถึง "ลบนี่" มันจะหายไปและลบมัน แต่เมื่อวัตถุออกจากขอบเขตมันจะเรียก destructor destructor จะพยายามลบอีกครั้งและจากนั้นคุณถูก hosed ในอดีตการทำสิ่งนี้จะทำให้โปรแกรมไม่เพียง แต่ระบบปฏิบัติการและคอมพิวเตอร์จะต้องเริ่มต้นใหม่ ไม่ว่าในกรณีใดก็ตามไม่แนะนำอย่างยิ่งและควรหลีกเลี่ยงเกือบตลอดเวลา ฉันจะต้องหมดหวังฉาบอย่างจริงจัง


7
+1 ฉันไม่เข้าใจว่าทำไมคุณถึงถูกลดระดับลง "ควรเขียน C ++ เพื่อให้ทำงานได้ไม่ว่าคลาสนั้นจะสร้างอินสแตนซ์บนฮีปในอาร์เรย์หรือบนสแต็ก" เป็นคำแนะนำที่ดีมาก
Joh

1
คุณสามารถห่อวัตถุที่คุณต้องการลบตัวเองในคลาสพิเศษซึ่งจะลบวัตถุนั้นและใช้เทคนิคนี้เพื่อป้องกันการจัดสรรสแต็ก: stackoverflow.com/questions/124880/ ......มีบางครั้งที่ไม่มี ทางเลือกที่ทำงานได้ ฉันเพิ่งใช้เทคนิคนี้เพื่อลบเธรดที่เริ่มต้นด้วยฟังก์ชัน DLL ด้วยตนเอง แต่ฟังก์ชัน DLL ต้องส่งคืนก่อนที่เธรดจะสิ้นสุด
เฟลิกซ์ Dombek

คุณไม่สามารถโปรแกรมในลักษณะที่มีคนทำเพียงแค่คัดลอกและวางด้วยรหัสของคุณในทางที่ผิดมันต่อไป
จิมมี่ต

22

ได้รับอนุญาต (เพียงไม่ใช้วัตถุหลังจากนั้น) แต่ฉันจะไม่เขียนโค้ดดังกล่าวในทางปฏิบัติ ผมคิดว่าdelete thisควรจะปรากฏเฉพาะในฟังก์ชั่นที่เรียกว่าreleaseหรือและรูปลักษณ์ที่ชอบ:Releasevoid release() { ref--; if (ref<1) delete this; }


ซึ่งเป็นหนึ่งในทุกโครงการของฉัน ... :-)
cmaster - คืนสถานะโมนิกา

15

ในการก่อสร้าง Component Object Model (COM) delete thisสามารถเป็นส่วนหนึ่งของReleaseวิธีการที่เรียกว่าเมื่อใดก็ตามที่คุณต้องการที่จะปล่อยวัตถุที่ถูกซื้อ:

void IMyInterface::Release()
{
    --instanceCount;
    if(instanceCount == 0)
        delete this;
}

8

นี่คือสำนวนหลักสำหรับวัตถุที่นับการอ้างอิง

การนับการอ้างอิงเป็นรูปแบบที่แข็งแกร่งของการเก็บขยะแบบกำหนดค่า - ช่วยให้มั่นใจว่าวัตถุจะจัดการอายุการใช้งานของตัวเองแทนการใช้พอยน์เตอร์ที่ชาญฉลาดเป็นต้นเพื่อทำสิ่งเหล่านี้ วัตถุพื้นฐานนั้นเข้าถึงได้ผ่านตัวชี้อัจฉริยะ "อ้างอิง" ซึ่งได้รับการออกแบบเพื่อให้พอยน์เตอร์เพิ่มและลดจำนวนสมาชิก (จำนวนการอ้างอิง) ในวัตถุจริง

เมื่อการอ้างอิงล่าสุดลดลงจากสแต็กหรือถูกลบการนับการอ้างอิงจะเป็นศูนย์ พฤติกรรมเริ่มต้นของวัตถุของคุณจะเป็นการเรียก "ลบสิ่งนี้" ไปยังการรวบรวมขยะ - ไลบรารีที่ฉันเขียนให้การเรียก "CountIsZero" เสมือนที่ได้รับการป้องกันในคลาสพื้นฐานเพื่อให้คุณสามารถแทนที่ลักษณะการทำงานนี้สำหรับสิ่งต่าง ๆ เช่นการแคช

กุญแจสำคัญในการทำให้ความปลอดภัยนี้ไม่อนุญาตให้ผู้ใช้สามารถเข้าถึง CONSTRUCTOR ของวัตถุที่เป็นปัญหา (ทำให้มันได้รับการป้องกัน) แต่ทำให้พวกเขาเรียกสมาชิกแบบคงที่บางคน - โรงงานเหมือน "แบบคงที่อ้างอิง CreateT (... )" ด้วยวิธีนี้คุณจะรู้ได้อย่างแน่นอนว่ามันถูกสร้างขึ้นด้วย "ใหม่" ธรรมดาและไม่มีตัวชี้แบบดิบอยู่เลยดังนั้น "ลบสิ่งนี้" จะไม่ระเบิด


เหตุใดคุณจึงไม่สามารถมี "ตัวจัดสรร / ตัวรวบรวมขยะ" ในคลาส (อินเทอร์เฟซ) ซึ่งเป็นอินเทอร์เฟซที่การจัดสรรทั้งหมดเสร็จสิ้นแล้วและปล่อยให้คลาสนั้นจัดการการอ้างอิงทั้งหมดของการนับวัตถุ แทนที่จะบังคับให้วัตถุเหล่านี้รบกวนงานการรวบรวมขยะบางสิ่งที่ไม่เกี่ยวข้องอย่างสมบูรณ์กับวัตถุประสงค์ที่กำหนดไว้
Lundin

1
คุณสามารถทำให้ destructor ได้รับการป้องกันเพื่อห้ามการจัดสรรแบบคงที่และสแต็กของวัตถุของคุณ
Game_Overture

7

คุณสามารถทำได้ อย่างไรก็ตามคุณไม่สามารถมอบหมายสิ่งนี้ได้ ด้วยเหตุผลที่คุณระบุว่าทำเช่นนี้ "ฉันต้องการเปลี่ยนมุมมอง" ดูเหมือนเป็นเรื่องที่น่าสงสัยมาก วิธีที่ดีกว่าในความคิดของฉันจะเป็นวัตถุที่เก็บมุมมองเพื่อแทนที่มุมมองนั้น

แน่นอนคุณกำลังใช้วัตถุ RAII ดังนั้นคุณไม่จำเป็นต้องโทรลบเลย ... ใช่ไหม?


4

นี่เป็นคำถามที่เก่าแล้วตอบ แต่ @Alexandre ถามว่า "ทำไมทุกคนต้องการทำเช่นนี้" และฉันคิดว่าฉันอาจให้ตัวอย่างการใช้งานที่ฉันกำลังพิจารณาในบ่ายนี้

รหัสดั้งเดิม ใช้ตัวชี้เปล่า ๆ Obj * obj ด้วยการลบ obj ในตอนท้าย

น่าเสียดายที่บางครั้งฉันต้องการไม่บ่อยครั้งเพื่อให้วัตถุมีชีวิตอยู่อีกต่อไป

ฉันกำลังพิจารณาทำให้เป็นตัวชี้สมาร์ทการอ้างอิงนับ แต่จะมีรหัสมากมายที่จะเปลี่ยนถ้าฉันต้องใช้ref_cnt_ptr<Obj>ทุกที่ และถ้าคุณผสม Obj * เปล่าและ ref_cnt_ptr คุณสามารถลบวัตถุโดยปริยายเมื่อ ref_cnt_ptr สุดท้ายหายไปแม้ว่าจะมี Obj * ยังมีชีวิตอยู่

ดังนั้นฉันกำลังคิดเกี่ยวกับการสร้างชัดเจน _elete_ref_cnt_ptr คือตัวชี้นับที่อ้างอิงซึ่งการลบจะกระทำในรูทีนการลบอย่างชัดเจนเท่านั้น ใช้งานในที่เดียวที่โค้ดที่มีอยู่รู้อายุการใช้งานของวัตถุรวมถึงในรหัสใหม่ของฉันที่ทำให้วัตถุมีอายุการใช้งานยาวนานขึ้น

การเพิ่มและลดจำนวนการอ้างอิงที่ชัดเจนได้รับการจัดการ _ref_cnt_ptr

แต่ไม่ว่างเมื่อจำนวนการอ้างอิงถูกเห็นว่าเป็นศูนย์ใน destructor ชัดเจน_delete_ref_cnt_ptr

การทำให้ว่างเท่านั้นเมื่อการนับการอ้างอิงถูกเห็นว่าเป็นศูนย์ในการดำเนินการลบอย่างชัดเจน เช่นในสิ่งที่ชอบ:

template<typename T> class explicit_delete_ref_cnt_ptr { 
 private: 
   T* ptr;
   int rc;
   ...
 public: 
   void delete_if_rc0() {
      if( this->ptr ) {
        this->rc--;
        if( this->rc == 0 ) {
           delete this->ptr;
        }
        this->ptr = 0;
      }
    }
 };

ตกลงบางอย่างเช่นนั้น มันผิดปกติเล็กน้อยที่จะมีการนับประเภทตัวชี้การอ้างอิงไม่ลบวัตถุที่ชี้ไปในตัวทำลาย ptr ของ rc'ed โดยอัตโนมัติ แต่ดูเหมือนว่าสิ่งนี้อาจทำให้การผสมพอยน์เตอร์พอยน์เตอร์และพอยน์เตอร์ rc'ed ปลอดภัยขึ้นเล็กน้อย

แต่จนถึงตอนนี้ไม่จำเป็นต้องลบสิ่งนี้

แต่มันเกิดขึ้นกับฉัน: ถ้าวัตถุชี้ไปที่ Pointee รู้ว่ามันกำลังถูกนับการอ้างอิงเช่นถ้าการนับอยู่ภายในวัตถุ (หรือในตารางอื่น ๆ ) แล้ว delete_if_rc0 ประจำอาจเป็นวิธีการของ วัตถุ pointee ไม่ใช่ตัวชี้ (สมาร์ท)

class Pointee { 
 private: 
   int rc;
   ...
 public: 
   void delete_if_rc0() {
        this->rc--;
        if( this->rc == 0 ) {
           delete this;
        }
      }
    }
 };

จริงๆแล้วมันไม่จำเป็นต้องเป็นวิธีสมาชิกเลย แต่อาจเป็นฟังก์ชั่นฟรี:

map<void*,int> keepalive_map;
template<typename T>
void delete_if_rc0(T*ptr) {
        void* tptr = (void*)ptr;
        if( keepalive_map[tptr] == 1 ) {
           delete ptr;
        }
};

(BTW ฉันรู้ว่ารหัสไม่ถูกต้อง - มันจะอ่านได้น้อยลงถ้าฉันเพิ่มรายละเอียดทั้งหมดดังนั้นฉันจะปล่อยให้มันเป็นแบบนี้)


0

ลบสิ่งนี้ถูกกฎหมายตราบใดที่วัตถุยังอยู่ในกอง คุณจะต้องใช้วัตถุเป็นกองเท่านั้น วิธีเดียวที่จะทำเช่นนั้นคือเพื่อให้ destructor ได้รับการปกป้อง - วิธีนี้อาจถูกลบออกจากชั้นเรียนเท่านั้นดังนั้นคุณจะต้องมีวิธีการที่จะทำให้แน่ใจว่าการลบ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.