Mehr als tausend Worte:
#include<string>
#include<iostream>
class SayWhat {
public:
SayWhat& operator[](const std::string& s) {
std::cout<<"here\n"; // To make sure we fail on function entry
std::cout<<s<<"\n";
return *this;
}
};
int main() {
SayWhat ohNo;
// ohNo[1]; // Does not compile. Logic prevails.
ohNo[0]; // you didn't! this compiles.
return 0;
}
Der Compiler beschwert sich nicht, wenn er die Nummer 0 an den Bracket-Operator übergibt, der eine Zeichenfolge akzeptiert. Stattdessen wird dies kompiliert und schlägt vor dem Aufrufen der Methode fehl mit:
terminate called after throwing an instance of 'std::logic_error'
what(): basic_string::_S_construct null not valid
Als Referenz:
> g++ -std=c++17 -O3 -Wall -Werror -pedantic test.cpp -o test && ./test
> g++ --version
gcc version 7.3.1 20180303 (Red Hat 7.3.1-5) (GCC)
Meine Vermutung
Der Compiler verwendet implizit den std::string(0)
Konstruktor, um die Methode einzugeben, was das gleiche Problem (google den obigen Fehler) ohne guten Grund ergibt.
Frage
Gibt es überhaupt eine Möglichkeit, dies auf der Klassenseite zu beheben, sodass der API-Benutzer dies nicht spürt und der Fehler beim Kompilieren erkannt wird?
Das heißt, eine Überlastung hinzufügen
void operator[](size_t t) {
throw std::runtime_error("don't");
}
ist keine gute Lösung.
c++
string
std
implicit-conversion
Kabanus
quelle
quelle
operator[]()
, die einint
Argument akzeptiert , und definieren Sie es nicht.Antworten:
Der Grund
std::string(0)
ist gültig, weil0
er eine Nullzeigerkonstante ist. 0 entspricht also dem String-Konstruktor, der einen Zeiger nimmt. Dann läuft der Code gegen die Voraussetzung, dass man keinen Nullzeiger übergeben darfstd::string
.Nur das Literal
0
würde als Nullzeigerkonstante interpretiert, wenn es ein Laufzeitwert in einemint
wäre, hätten Sie dieses Problem nicht (da dann die Überlastungsauflösung stattdessen nach einerint
Konvertierung suchen würde ). Literal ist auch1
kein Problem, da1
es sich nicht um eine Nullzeigerkonstante handelt.Da es sich um ein Problem mit der Kompilierungszeit handelt (wörtlich ungültige Werte), können Sie es zur Kompilierungszeit abfangen. Fügen Sie eine Überladung dieses Formulars hinzu:
std::nullptr_t
ist die Art vonnullptr
. Und es wird passen jeden Null - Zeiger - Konstante, wäre es0
,0ULL
odernullptr
. Und da die Funktion gelöscht wird, verursacht sie während der Überlastungsauflösung einen Fehler bei der Kompilierung.quelle
std::string
den Konstruktor ist nach dem C ++ - Standard nicht zulässig. Es ist ein undefiniertes Verhalten, sodass MSVC tun kann, was es will (z. B. eine Ausnahme auslösen).Eine Möglichkeit besteht darin, eine
private
Überladung zu deklarierenoperator[]()
, die ein integrales Argument akzeptiert, und es nicht zu definieren.Diese Option funktioniert mit allen C ++ - Standards (ab 1998), im Gegensatz zu Optionen,
void operator[](std::nullptr_t) = delete
die ab C ++ 11 gültig sind.Wenn Sie
operator[]()
einprivate
Mitglied erstellen, wird in Ihrem Beispiel ein diagnostizierbarer Fehler verursachtohNo[0]
, es sei denn, dieser Ausdruck wird von einer Mitgliedsfunktion oderfriend
der Klasse verwendet.Wenn dieser Ausdruck von einer Mitgliedsfunktion oder
friend
der Klasse verwendet wird, wird der Code kompiliert, aber - da die Funktion nicht definiert ist - schlägt der Build im Allgemeinen fehl (z. B. ein Linkerfehler aufgrund einer undefinierten Funktion).quelle