Bisakah ada objek implisit yang berbeda berdasarkan keputusan runtime nanti di C ++ 20?

11

Pertanyaan ini mengacu pada penambahan P0593 ke draft C ++ 20 terbaru .

Ini contoh saya:

#include <cstdlib>
#include <cstdio>

void foo(void *p)
{
    if ( std::getchar() == 'i' )
    {
        *(int *)p = 2;
        std::printf("%d\n", *(int *)p);
    }
    else
    {
        *(float *)p = 2;
        std::printf("%f\n", *(float *)p);
    }
}

int main()
{
    void *a = std::malloc( sizeof(int) + sizeof(float) );
    if ( !a ) return EXIT_FAILURE;

    foo(a);
    // foo(a);    [2]
}

Apakah kode ini didefinisikan dengan baik untuk semua input di bawah konsep terbaru?

Dasar pemikiran yang dinyatakan dalam P0593 membuatnya cukup jelas bahwa tidak memberi komentar [2]akan menyebabkan perilaku tidak terdefinisi karena pelanggaran aliasing yang ketat, jika dua item input pengguna berbeda. Penciptaan objek implisit seharusnya terjadi hanya sekali, pada titik malloc; itu tidak dipicu oleh pernyataan penugasan di foo.

Untuk menjalankan program yang sebenarnya, ada anggota dari set objek implisit yang tidak ditentukan yang akan membuat program didefinisikan dengan baik. Tetapi tidak jelas bagi saya apakah pilihan penciptaan objek implisit yang disebutkan dalam [intro.object] / 10 harus dilakukan ketika hal itu mallocterjadi; atau apakah keputusan itu dapat "perjalanan waktu".

Masalah yang sama mungkin muncul untuk program yang membaca gumpalan biner menjadi buffer dan kemudian membuat keputusan runtime tentang bagaimana mengaksesnya (mis deserialization; dan header memberitahu kita apakah float atau int akan muncul).

MM
sumber

Jawaban:

9

Penciptaan objek implisit seharusnya terjadi hanya sekali, pada titik malloc; itu tidak dipicu oleh pernyataan penugasan di foo.

Itu tidak relevan. Yang penting adalah objek mana yang akan dibuat. Standar mengatakan bahwa objek yang akan dibuat adalah sesuatu yang membuat sesuatu menjadi UB menjadi kode yang terdefinisi dengan baik:

operasi yang secara implisit menciptakan dan memulai masa hidup nol atau lebih objek dari tipe seumur hidup implisit ([basic.types]) di wilayah penyimpanan yang ditentukan jika melakukan hal itu akan mengakibatkan program memiliki perilaku yang telah ditentukan.

Perilaku pada akhirnya didasarkan pada eksekusi runtime, bukan analisis statis. Jadi, Anda hanya perlu mengikuti eksekusi program sampai Anda menemukan kasus di mana perilaku tidak akan didefinisikan, namun akan ditentukan jika objek dari beberapa jenis telah dibuat dalam penyimpanan itu pada saat operasi yang bersangkutan.

Jadi lokasi penciptaan selalu "operasi", tetapi penentuan apa yang akan dibuat didasarkan pada bagaimana memori digunakan saat runtime (yaitu: perilaku).

Nicol Bolas
sumber
2
Agar jelas, Anda mengatakan bahwa kode saya terdefinisi dengan baik?
MM
2
@ MM: Itu benar.
Nicol Bolas