Pertimbangkan program berikut:
#include<stdexcept>
#include<iostream>
int main() {
try {
throw std::range_error(nullptr);
} catch(const std::range_error&) {
std::cout << "Caught!\n";
}
}
GCC dan Dentang dengan libstdc ++ panggilan std::terminate
dan batalkan program dengan pesan
terminate called after throwing an instance of 'std::logic_error'
what(): basic_string::_S_construct null not valid
Dibatasi dengan libc ++ segfault pada konstruksi pengecualian.
Lihat godbolt .
Apakah kompiler berperilaku sesuai standar? Bagian yang relevan dari standar [diagnosticics.range.error] (C ++ 17 N4659) memang mengatakan bahwa std::range_error
memiliki const char*
kelebihan konstruktor yang harus dipilih lebih dari const std::string&
kelebihan. Bagian ini juga tidak menyatakan prasyarat apa pun pada konstruktor dan hanya menyatakan prasyarat tersebut
Postconditions :
strcmp(what(), what_arg) == 0
.
Postcondition ini selalu memiliki perilaku yang tidak terdefinisi jika what_arg
adalah null pointer, jadi apakah ini berarti bahwa program saya juga memiliki perilaku yang tidak terdefinisi dan bahwa kedua kompiler bertindak sesuai? Jika tidak, bagaimana seharusnya seseorang membaca postconditions yang tidak mungkin dalam standar?
Setelah dipikir-pikir, saya pikir itu harus berarti perilaku yang tidak terdefinisi untuk program saya, karena jika tidak maka pointer (valid) yang tidak menunjuk ke string null juga akan diizinkan, yang jelas tidak masuk akal.
Jadi, dengan asumsi itu benar, saya ingin memfokuskan pertanyaan lebih pada bagaimana standar menyiratkan perilaku yang tidak terdefinisi ini. Apakah itu mengikuti dari ketidakmungkinan postkondisi bahwa panggilan itu juga memiliki perilaku yang tidak terdefinisi atau apakah prasyarat itu dilupakan begitu saja?
Terinspirasi oleh pertanyaan ini .
sumber
what()
saatnullptr
diteruskan mungkin akan menyebabkan masalah.nullptr
dilewati, saya akan berpikir bahwa sayawhat()
harus melakukan dereferensi di beberapa titik untuk mendapatkan nilai. Itu akan menjadi dereferencingnullptr
, yang paling bermasalah dan pasti untuk crash adalah yang terburuk.strcmp
digunakan untuk menggambarkan nilaiwhat_arg
. Itulah yang dikatakan bagian yang relevan dari standar C , yang disebut dengan spesifikasi<cstring>
. Tentu saja kata-katanya bisa lebih jelas.Jawaban:
Dari dokumen :
Ini menunjukkan mengapa Anda mendapatkan segfault, api benar-benar memperlakukannya sebagai string nyata. Secara umum di cpp jika ada yang opsional, akan ada konstruktor / fungsi yang berlebihan yang tidak mengambil apa yang tidak perlu. Jadi melintas
nullptr
untuk suatu fungsi yang tidak mendokumentasikan sesuatu menjadi opsional akan menjadi perilaku yang tidak terdefinisi. Biasanya API tidak mengambil pointer dengan pengecualian untuk string C. Jadi IMHO aman untuk mengasumsikan melewati nullptr untuk fungsi yang mengharapkanconst char *
, akan menjadi perilaku yang tidak terdefinisi. API yang lebih baru mungkin lebih sukastd::string_view
untuk kasus-kasus itu.Memperbarui:
Biasanya adil untuk mengasumsikan C ++ API mengambil pointer untuk menerima NULL. Namun string C adalah kasus khusus. Hingga
std::string_view
, tidak ada cara yang lebih baik untuk melewatinya dengan efisien. Secara umum untuk menerima APIconst char *
, asumsi harus adalah bahwa itu harus menjadi string C yang valid. yaitu pointer ke urutanchar
s yang berakhir dengan '\ 0'.range_error
dapat memvalidasi bahwa pointer tidaknullptr
tetapi itu tidak dapat memvalidasi jika itu diakhiri dengan '\ 0'. Jadi lebih baik tidak melakukan validasi apa pun.Saya tidak tahu persis kata-kata dalam standar, tetapi pra-kondisi ini mungkin diasumsikan secara otomatis.
sumber
Ini kembali ke pertanyaan dasar apakah OK untuk membuat std :: string dari nullptr? dan apa yang harus dilakukan?
www.cplusplus.com mengatakan
Jadi ketika
disebut implementasi mencoba membuat sesuatu seperti
yang tidak terdefinisi. Yang saya anggap bug (tanpa membaca kata-kata aktual dalam standar). Sebaliknya para pengembang libery bisa membuat sesuatu seperti
Tapi kemudian catcher harus memeriksa nullptr
what();
atau hanya akan crash di sana. Jadistd::range_error
harus menetapkan string kosong atau "(nullptr)" seperti beberapa bahasa lain.sumber
std::string
danstd::string
konstruktor tidak boleh dipilih dengan resolusi kelebihan beban.const char *
kelebihan dipilih oleh resolusi yang berlebihan