operator baru () berperilaku berbeda ketika operator menghapus () dihapus tergantung pada keberadaan konstruktor default

17

Membuat objek baru kelas C dengan operator baru () memberikan kesalahan di sini:

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

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


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

dengan C2280: 'void C::operator delete(void *)': function was explicitly deleted

Tetapi ketika saya mengganti C() {} dengan C() = default; atau menghapus baris sehingga kompiler menyisipkan konstruktor default (yang saya percaya memiliki efek yang sama dengan = default), kode akan dikompilasi dan dijalankan.

Apa perbedaan antara konstruktor default yang dibuat kompiler dan konstruktor default yang ditentukan pengguna yang membuat ini terjadi?

Saya mendapat beberapa petunjuk dalam posting ini , tetapi kelas C di sini (tanpa konstruktor yang disediakan pengguna) tidak sepele karena destruktornya virtual, bukan?

Dikompilasi dengan Visual Studio terbaru, c ++ 17.

yeshjho
sumber
3
Tidak yakin, tapi saya pikir perbedaannya adalah konstruktor defaultnya adalahnoexcept
Sebastian Redl
1
Tidak dapat mereproduksi dengan g ++. Diagnosis serupa mengenai operator delete()apakah konstruktor ditulis secara manual atau secara implisit dihasilkan. Yang konsisten dengan harapan saya - karena pengecualian dapat dilemparkan oleh newekspresi, kompiler perlu mengakses operator delete().
Peter
@SebastianRedl Anda benar, menambahkan noexceptakan membuat kompilasi kode, tetapi bagaimana ...?
yeshjho
1
@ Peter Pengecualian hanya bisa dilemparkan oleh konstruktor, jadi jika itu noexceptseperti yang disebutkan SebastianRedl, maka panggilan untuk operator deletetidak perlu disertakan. Juga g ++ tidak hanya mengeluh jika destructor itu virtual. Kalau tidak selalu mengkompilasi, bahkan jika konstruktor melempar.
walnut
@LeDYoM Tautan Anda tentang penguraian alamat IP, yang tampaknya tidak relevan dengan pertanyaan. Apakah Anda memposting tautan yang salah?
LF

Jawaban:

17

Apa perbedaan antara konstruktor default yang dibuat kompiler dan konstruktor default yang ditentukan pengguna yang membuat ini terjadi?

newEkspresi memanggil korespondensi operator newdan kemudian memanggil konstruktor. Jika konstruktor melempar newekspresi pengecualian harus membatalkan efek operator new(untuk menghindari kebocoran memori) dengan memanggil yang sesuai operator delete. Jika yang terakhir dihapus, newekspresi tidak dapat memanggil yang menghasilkan kompiler error: use of deleted function 'static void C::operator delete(void*)'.

Sebuah noexceptkonstruktor tidak mungkin melempar pengecualian, maka, sesuai operator deletetidak perlu karena tidak akan dipanggil oleh newekspresi. Sebuah defaultkonstruktor dari kelas sepele juga merupakan noexceptkonstruktor. Kehadiran destruktor virtual operator deleteharus non-dihapus karena destruktor penghapusan skalar khusus (detail implementasi untuk memungkinkan deleteekspresi melalui pointer kelas dasar) memanggil operator delete.

Tampaknya tidak ditentukan oleh standar C ++ apakah kompiler harus diharuskan operator deleteuntuk tidak dihapus bahkan jika itu tidak dapat dipanggil dengan newekspresi. gcc, bagaimanapun, sepertinya tidak menggunakan korespondensi operator deletedalam newekspresi sama sekali jika deleted (memposting laporan bug ).

Maxim Egorushkin
sumber