ตัวดำเนินการใหม่ () ทำงานแตกต่างกันเมื่อตัวดำเนินการลบ () ถูกลบทั้งนี้ขึ้นอยู่กับการมีอยู่ของตัวสร้างเริ่มต้น


17

การสร้างออบเจ็กต์ใหม่ของคลาส C โดยมีโอเปอเรเตอร์ new () ให้ข้อผิดพลาดที่นี่:

class C
{
public:
    C() {}
    virtual ~C() {}

    void operator delete(void*) = delete;
};


int main()
{
    C* c = new C;
}

กับ C2280: 'void C::operator delete(void *)': function was explicitly deleted

แต่เมื่อฉันแทนที่C() {} ด้วยC() = default; หรือลบบรรทัดเพื่อให้คอมไพเลอร์แทรกตัวสร้างเริ่มต้น (ซึ่งฉันเชื่อว่ามีผลเหมือนกันกับ= default) รหัสจะรวบรวมและเรียกใช้

อะไรคือความแตกต่างระหว่างตัวสร้างเริ่มต้นที่คอมไพเลอร์ที่สร้างโดยผู้ใช้ที่กำหนดโดยค่าเริ่มต้นที่ทำให้สิ่งนี้เกิดขึ้น?

ฉันได้รับคำแนะนำบางอย่างในการโพสต์นี้แต่คลาส C ที่นี่ (ไม่มีคอนสตรัคเตอร์ที่ผู้ใช้ให้) ไม่น่าสนใจเลยเพราะ destructor เป็นเสมือนจริงใช่ไหม

คอมไพล์ด้วย Visual Studio ล่าสุด c ++ 17


3
ไม่แน่ใจ แต่ฉันคิดว่าความแตกต่างคือคอนสตรัคเตอร์ผิดนัดคือnoexcept
เซบาสเตียนเรดล

1
ไม่สามารถสร้างซ้ำด้วย g ++ การวินิจฉัยที่คล้ายกันเกี่ยวกับoperator delete()ว่าคอนสตรัคถูกเขียนด้วยตนเองหรือสร้างขึ้นโดยปริยาย ซึ่งสอดคล้องกับความคาดหวังของฉัน - ตั้งแต่ข้อยกเว้นอาจจะโยนโดยการแสดงออกของคอมไพเลอร์ต้องการที่จะเข้าถึงnew operator delete()
ปีเตอร์

@SebastianRedl คุณถูกต้องการเพิ่มnoexceptจะทำให้การคอมไพล์รหัส แต่อย่างไร ... ?
yeshjho

1
@ Peter ข้อยกเว้นสามารถถูกสร้างขึ้นได้โดยตัวสร้างเท่านั้นดังนั้นหากเป็นไปnoexceptตามที่ SebastianRedl พูดถึงคุณoperator deleteไม่จำเป็นต้องรวมการเรียกไปยัง นอกจากนี้ g ++ จะบ่นเฉพาะเมื่อ destructor นั้นเป็นเสมือน มิฉะนั้นจะรวบรวมทุกครั้งแม้ว่าตัวสร้างจะขว้าง
วอลนัท

@LeDYoM ลิงก์ของคุณเกี่ยวกับการแยกที่อยู่ IP ซึ่งดูเหมือนจะไม่เกี่ยวข้องกับคำถาม คุณโพสต์ลิงก์ผิดหรือเปล่า?
LF

คำตอบ:


17

อะไรคือความแตกต่างระหว่างตัวสร้างเริ่มต้นที่คอมไพเลอร์ที่สร้างโดยผู้ใช้ที่กำหนดโดยค่าเริ่มต้นที่ทำให้สิ่งนี้เกิดขึ้น?

newexpression เรียกสิ่งที่เกี่ยวข้องoperator newแล้วเรียก constructor หากสร้างพ่นยกเว้นnewการแสดงออกต้องยกเลิกผลของการoperator new(หน่วยความจำรั่วหลีกเลี่ยง) operator deleteโดยการเรียกที่สอดคล้องกัน ถ้าหลังถูกลบแสดงออกไม่สามารถเรียกมันซึ่งผลในการคอมไพเลอร์newerror: use of deleted function 'static void C::operator delete(void*)'

คอนnoexceptสตรัคเตอร์ไม่สามารถโยนข้อยกเว้นได้ดังนั้นจึงoperator deleteไม่จำเป็นต้องมีสิ่งที่เกี่ยวข้องเนื่องจากnewนิพจน์จะไม่ถูกเรียก คอนdefaultสตรัคของคลาสที่ไม่สำคัญก็เป็นคอนnoexceptสตรัคเตอร์เช่นกัน การปรากฏตัวของ destructor เสมือนต้องoperator deleteที่จะไม่เป็นลบเนื่องจากพิเศษลบ destructor สเกลาร์ (รายละเอียดการดำเนินการเพื่อให้สามารถใช้deleteการแสดงออกผ่านตัวชี้ระดับฐาน) operator deleteจะเรียก

ดูเหมือนว่าจะไม่ได้ระบุโดยมาตรฐาน C ++ ว่าคอมไพเลอร์จะต้องoperator deleteไม่ถูกลบแม้ว่ามันจะไม่สามารถเรียกได้โดยnewการแสดงออก gccแต่ดูเหมือนจะไม่ได้รับการกล่าวอ้างที่สอดคล้องกันoperator deleteในnewการแสดงออกที่ทุกคนถ้ามันเป็นdeleted (โพสต์รายงานข้อผิดพลาด )

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