Mengapa kita tidak dapat membuat objek yang dapat dibangun dengan menggunakan malloc jika konstruktor standar sepele tidak melakukan tindakan?

14

Saya mengalami kesulitan dalam memahami paragraf berikut yang dikutip dari cppreference tentang konstruktor standar sepele. Saya telah mencari stackoverflow tetapi masih belum mendapatkan jawaban yang jelas. Jadi tolong bantu.

Konstruktor default sepele adalah konstruktor yang tidak melakukan tindakan. Semua tipe data yang kompatibel dengan bahasa C (tipe POD) sepele-standar dibangun. Namun, tidak seperti dalam C, objek dengan konstruktor standar sepele tidak dapat dibuat hanya dengan menafsirkan kembali penyimpanan yang selaras, seperti memori yang dialokasikan dengan std :: malloc: penempatan-baru diperlukan untuk secara resmi memperkenalkan objek baru dan menghindari kemungkinan perilaku yang tidak terdefinisi.

Khususnya, jika konstruktor default sepele tidak melakukan apa-apa, mengapa kita tidak bisa menafsirkan kembali penyimpanan dan berpura-pura ada objek dengan tipe yang diberikan? Bisakah Anda memberikan beberapa contoh untuk kemungkinan perilaku tidak terdefinisi yang akan ditimbulkan oleh ini?

Liu Sha
sumber
Pekerjaan yang paling penting dari sebuah kompiler adalah untuk tidak mengkompilasi kode sumber tetapi untuk menolak kemungkinan kode yang tidak valid. Tidak dapat melakukan ini ketika Anda menggunakan malloc ().
Hans Passant
6
Alasannya sangat sederhana. Semakin sedikit peluang bagi programmer untuk melakukan hal-hal gila, semakin banyak peluang bagi kompiler untuk melakukan hal-hal gila (optimisasi agresif).
n. 'kata ganti' m.
1
Untuk alasan serupa Anda tidak bisa adil *reinterpret_cast<float*>(&someNonFloatObject) = 0.1f;. C ++ memiliki konsep objek dan masa hidup objek, yang ditentukan pada mesin abstrak, dan hanya karena tidak ada instruksi CPU untuk membuat objek dari penyimpanan tidak berarti bahwa tidak ada perbedaan pada mesin abstrak.
Max Langhof
1
@HansPassant Kompiler yang menolak semua kode menolak semua kode yang tidak valid. Lagi pula, bukan tugas copiler untuk menolak program yang memiliki UB.
n. 'kata ganti' m.
1
stackoverflow.com/q/52154744
StoryTeller - Unslander Monica

Jawaban:

7

P0593R5 memberikan contoh ini:

struct X { int a, b; };
X *make_x() {
  X *p = (X*)malloc(sizeof(struct X));
  p->a = 1;
  p->b = 2;
  return p;
}

dan menjelaskan:

Ketika dikompilasi dengan kompiler C ++, kode ini memiliki perilaku yang tidak terdefinisi, karena p-> upaya untuk menulis ke sub-objek int dari objek X, dan program ini tidak pernah membuat objek X maupun int sub-objek.

Per [intro.object] p1,

Objek dibuat oleh definisi, oleh ekspresi-baru, ketika secara implisit mengubah anggota aktif serikat, atau ketika objek sementara dibuat.

... dan program ini tidak melakukan hal-hal ini.

Dalam praktiknya ini berhasil dan situasi UB dianggap lebih sebagai cacat dalam standar daripada yang lainnya. Seluruh tujuan dari makalah ini adalah untuk mengusulkan cara untuk memperbaiki masalah itu dan kasus-kasus serupa tanpa melanggar hal-hal lain.

Pemrogram
sumber
1

Untuk alasan "murni".

Alternatif dan status quo aktual adalah bahwa setiap wilayah penyimpanan akan berisi semua objek yang cocok dalam penyimpanan itu, pada saat yang sama. Beberapa anggota komite tidak nyaman dengan status quo dan banyak orang takut gagasan memiliki banyak objek di tempat yang sama (dalam keadaan virtual dan tidak diinisialisasi).

Tidak ada yang pernah mampu menunjukkan masalah logika dengan memiliki banyak objek di wilayah penyimpanan yang tak terhingga banyaknya.

Karena mereka memiliki bagian berbeda dari standar yang mengatakan hal-hal yang bertentangan, anggota komite hanya memutuskan untuk menganggap serius salah satu bagian terburuk dari standar.

Juga, menggunakan string literal sangat tidak diperbolehkan, jika Anda benar-benar menganggap serius satu bagian dari standar itu.

curiousguy
sumber
menggunakan string literal sangat tidak diperbolehkan dalam akta. Ada masalah CWG serupa tentang type_infoobjek. Sudahkah Anda melaporkan tentang string literal?
Pengacara Bahasa