[dcl.attr.noreturn] memberikan contoh berikut:
[[ noreturn ]] void f() {
throw "error";
// OK
}
tapi saya tidak mengerti apa gunanya [[noreturn]]
, karena tipe kembalinya fungsi sudah void
.
Jadi, apa gunanya noreturn
atribut itu? Bagaimana seharusnya digunakan?
c++
c++11
attributes
noreturn
BЈовић
sumber
sumber
Jawaban:
Atribut noreturn seharusnya digunakan untuk fungsi yang tidak kembali ke pemanggil. Itu tidak berarti fungsi batal (yang memang kembali ke pemanggil - mereka hanya tidak mengembalikan nilai), tetapi fungsi di mana aliran kontrol tidak akan kembali ke fungsi panggilan setelah fungsi selesai (mis. Fungsi yang keluar dari aplikasi, loop selamanya atau membuang pengecualian seperti pada contoh Anda).
Ini dapat digunakan oleh kompiler untuk melakukan beberapa optimasi dan menghasilkan peringatan yang lebih baik. Sebagai contoh jika
f
memiliki atribut noreturn, kompiler dapat memperingatkan Anda tentangg()
kode mati ketika Anda menulisf(); g();
. Demikian pula kompiler akan tahu untuk tidak memperingatkan Anda tentang pernyataan pengembalian yang hilang setelah panggilan kef()
.sumber
execve
itu yang seharusnya tidak kembali tetapi bisa ? Haruskah ia memiliki atribut noreturn ?noreturn
atribut.noreturn
hanya dapat digunakan jika fungsi Anda dijamin untuk melakukan sesuatu yang menghentikan program sebelum aliran kontrol dapat kembali ke pemanggil - misalnya karena Anda memanggil keluar (), batalkan (), nyatakan (0), dll.noreturn
. Menangani pengecualian itu tidak sama dengan mengembalikannya. Kode apa pun dalamtry
setelah panggilan masih tidak dapat dijangkau, dan jika tidakvoid
maka penugasan atau penggunaan nilai pengembalian tidak akan terjadi.noreturn
tidak memberi tahu kompiler bahwa fungsi tidak mengembalikan nilai apa pun. Ini memberitahu kompiler bahwa aliran kontrol tidak akan kembali ke pemanggil . Hal ini memungkinkan kompiler untuk membuat berbagai optimisasi - ia tidak perlu menyimpan dan mengembalikan keadaan volatile apa pun di sekitar panggilan, dapat mematikan kode menghilangkan kode apa pun yang akan mengikuti panggilan, dll.sumber
Ini berarti bahwa fungsi tidak akan selesai. Aliran kontrol tidak akan pernah mencapai pernyataan setelah panggilan ke
f()
:Informasi dapat digunakan oleh kompiler / pengoptimal dengan berbagai cara. Kompiler dapat menambahkan peringatan bahwa kode di atas tidak dapat dijangkau, dan dapat memodifikasi kode aktual
g()
dengan berbagai cara misalnya untuk mendukung kelanjutan.sumber
-Wno-return
dan Anda akan mendapatkan peringatan. Mungkin bukan yang Anda harapkan tetapi mungkin cukup untuk memberi tahu Anda bahwa kompiler memiliki pengetahuan tentang apa[[noreturn]]
itu dan dapat mengambil keuntungan darinya. (Saya sedikit terkejut bahwa-Wunreachable-code
itu tidak masuk ...)-Wmissing-noreturn
, peringatan menyiratkan bahwa analisis aliran menentukan bahwastd::cout
tidak dapat dijangkau. Saya tidak punya gcc yang cukup baru di tangan untuk melihat perakitan yang dihasilkan, tapi saya tidak akan terkejut jika panggilan untukoperator<<
dijatuhkan-O1
sudah cukup untuk menjatuhkan kode yang tidak terjangkau tanpa[[noreturn]]
petunjuk.[[noreturn]]
dari kode. Jika unit terjemahan ini hanya memiliki deklarasi fungsi yang didefinisikan di tempat lain, kompiler tidak akan dapat melepaskan kode itu, karena tidak tahu bahwa fungsi tidak kembali. Di situlah atribut harus membantu kompiler.Jawaban sebelumnya dengan benar menjelaskan apa itu noreturn, tetapi bukan mengapa itu ada. Saya tidak berpikir komentar "optimisasi" adalah tujuan utama: Fungsi yang tidak kembali jarang dan biasanya tidak perlu dioptimalkan. Sebaliknya saya pikir alasan utama dari noreturn adalah untuk menghindari peringatan positif palsu. Sebagai contoh, pertimbangkan kode ini:
Seandainya batalkan () tidak ditandai "noreturn", kompiler mungkin telah memperingatkan tentang kode ini memiliki lintasan di mana f tidak mengembalikan integer seperti yang diharapkan. Tetapi karena batalkan () ditandai tidak kembali ia tahu kode itu benar.
sumber
Jenis berbicara secara teoritis,
void
adalah apa yang disebut dalam bahasa lainunit
atautop
. Setara logisnya adalah Benar . Nilai apa pun dapat dilemparkan kevoid
(setiap jenis adalah subtipe darivoid
) secara sah . Pikirkan itu sebagai set "semesta"; tidak ada operasi yang sama untuk semua nilai di dunia, jadi tidak ada operasi yang valid pada nilai tipevoid
. Dengan kata lain, memberi tahu Anda bahwa sesuatu milik alam semesta tidak memberi Anda informasi apa pun - Anda sudah mengetahuinya. Jadi yang berikut adalah suara:Namun tugas di bawah ini bukan:
[[noreturn]]
, Di sisi lain, disebut kadang-kadangempty
,Nothing
,Bottom
atauBot
dan adalah setara logis dari False . Tidak memiliki nilai sama sekali, dan ekspresi tipe ini dapat dilemparkan ke (yaitu subtipe dari) tipe apa pun. Ini adalah set kosong. Perhatikan bahwa jika seseorang memberi tahu Anda "nilai ekspresi foo () milik set kosong" itu sangat informatif - ia memberi tahu Anda bahwa ungkapan ini tidak akan pernah menyelesaikan eksekusi normalnya; itu akan membatalkan, melempar atau menggantung. Ini adalah kebalikan darivoid
.Jadi yang berikut ini tidak masuk akal (pseudo-C ++, karena
noreturn
bukan tipe C ++ kelas satu)Tetapi penugasan di bawah ini benar-benar sah, karena
throw
dipahami oleh kompiler untuk tidak kembali:Di dunia yang sempurna, Anda bisa menggunakan
noreturn
sebagai nilai balik untuk fungsi diraise()
atas:Sayangnya C ++ tidak memungkinkan, mungkin karena alasan praktis. Sebaliknya itu memberi Anda kemampuan untuk digunakan
[[ noreturn ]]
atribut yang membantu membimbing optimasi dan peringatan kompiler.sumber
void
danvoid
tidak pernah dievaluasi ketrue
ataufalse
atau apa pun.true
, saya tidak bermaksud "nilaitrue
dari tipebool
" tetapi pengertian logika, lihat korespondensi Curry-Howard(void)true;
sangat valid, seperti jawabannya.void(true)
adalah sesuatu yang sama sekali berbeda, secara sintaksis. Ini adalah upaya untuk membuat objek tipe baruvoid
dengan memanggil konstruktor dengantrue
sebagai argumen; ini gagal, antara lain, karenavoid
bukan kelas satu.