Wird `new` in` new int;` als Operator betrachtet?

80

Der Ausdruck new int;wie in int * x = new int;ist ein neuer Ausdruck . Der Begriff "neuer Operator" scheint synonym mit "neuer Ausdruck" verwendet zu werden, zum Beispiel in dieser Frage: Unterschied zwischen "neuer Operator" und "neuer Operator"?

Ist es richtig zu sagen, dass das Schlüsselwort, newwie es in einem neuen Ausdruck verwendet wird, ein Operator ist? Warum oder warum nicht?

Wenn nicht, gibt es eine andere Rechtfertigung dafür, einen neuen Ausdruck "neuer Operator" zu nennen?

Ich habe Probleme, eine maßgebliche Definition für das zu finden, was einen Operator ausmacht.

Ich verstehe bereits die Unterscheidung zwischen dem Operator new, der einem Objekt Speicher zuweist, und dem "neuen Ausdruck", der möglicherweise einen aufruft operator new.

François Andrieux
quelle
4
@ Rogue - Die Sache ist, newist wie sizeofhier. Und ich denke, die Mehrheit der C ++ - Community denkt an sizeofeinen Operator. Der Standard bezieht sich bei der sizeofBeschreibung seiner Auswirkungen sogar auf den " Operator".
StoryTeller - Unslander Monica
2
@ StoryTeller-UnslanderMonica also weiter von meinem zweiten Kommentar (jetzt zu einer Antwort verschoben), mit sizeof, ich würde sagen, das wäre der Operator eines Ausdrucks sizeof(<type>). Und +ist ein Operator für einen unären Ausdruck <type> <op> <type>. Das ist zumindest meine Erkenntnis zum Mitnehmen. Sie können mich gerne korrigieren.
Schurke
2
@ Rogue - In der Tat. Aus diesem Grund würde ich argumentieren, dass der normative Text eher willkürlich ist, wenn man sich auf einen als Operator bezieht, während man sich nicht auf den anderen bezieht.
StoryTeller - Unslander Monica
1
Eine Randnotiz zur akzeptierten Antwort: Unabhängig davon, ob newes sich um einen Operator handelt oder nicht, gibt es einen Unterschied zwischen einem Ausdruck und einem Operator. ZB new intist ein Ausdruck, wie er zu etwas auswertet. Wenn newes sich um einen Operator handelt, ist nur der "neue" Teil new intder Operator (dh es ist eine eigene Sache). Konzeptionell ist ein Operator etwas, das auf etwas anderes einwirkt.
Filip Milovanović

Antworten:

134

newin new intgilt nicht als Betreiber. Es wird auch nicht als kein Betreiber angesehen.

Der C ++ - Standard ist wirklich vage und sogar inkonsistent, was einen "Operator" ausmacht. Beim Auflisten von Operatoren (wie beim Lexieren und Vorverarbeiten definiert) werden diese zusammen mit "Interpunktionszeichen" (z. B. () aufgelistet, es werden jedoch nie wirklich Regeln für Interpunktionszeichen im Allgemeinen angegeben. Es wird newsowohl als Schlüsselwort als auch als Operator aufgeführt. Es wird sizeofin der Gruppe der Schlüsselwörter aufgeführt, jedoch NICHT in der Gruppe der Operatoren, wird jedoch später als Operator bezeichnet.

Das Wichtigste dabei ist, dass sich das C ++ - Standardkomitee nicht allzu sehr mit der Trennung der lexikalischen Welt in "Operatoren" und "Nichtoperatoren" befasst. Dies liegt daran, dass dies nicht wirklich erforderlich ist. Es gibt keine grammatikalischen Regeln, die für alle Operatoren oder alle Nichtoperatoren gelten. Wichtige Sätze, wie der Satz überladbarer Operatoren, werden separat angegeben. Grammatikregeln für Dinge wie binäre arithmetische Ausdrücke werden einzeln angegeben.

Grundsätzlich ist "Operator" keine Kategorie, die für die C ++ - Sprache formal von Bedeutung ist. Daher wird jede kategoriale Antwort darauf basieren, wie sie sich "anfühlt". Sie können es als Operator bezeichnen, wenn Sie möchten, aber Sie können es auch als Schlüsselwort (oder Interpunktionszeichen!) Nennen, und der Sprachstandard wird Ihnen nicht widersprechen.

Sneftel
quelle
5
Sowohl der C- als auch der C ++ - Standard sind in Bezug auf einen Großteil ihrer Terminologie schlampig, da sie erwarteten, dass die Leser schließen würden, was gemeint ist, wenn es Lücken oder Unklarheiten gibt, anstatt zu überlegen, ob sie solche Auslassungen verwenden könnten, um "Optimierungen" zu rechtfertigen "In Fällen hätten die Autoren der Standards dies für ausreichend absurd gehalten, so dass es nicht erforderlich war, sie ausdrücklich zu verbieten."
Supercat
15

Ist es richtig zu sagen, dass das Schlüsselwort, newwie es in einem neuen Ausdruck verwendet wird, ein Operator ist? Warum oder warum nicht?

Nein. Das newin einem neuen Ausdruck ist ein Schlüsselwort, das einen neuen Ausdruck identifiziert .

Ein neuer Ausdruck ruft ein operator newoder operator new[]auf, um Speicherplatz zu erhalten. Außerdem wird dieser Speicher initialisiert und die Zuordnung (mit operator deleteoder operator delete[]) aufgehoben, wenn die Initialisierung ausgelöst wird.

Es gibt eine klare Unterscheidung, die operator newnur als überladbare, vom Benutzer austauschbare Funktion bezeichnet wird, und ein neuer Ausdruck kann mehr als nur diese Funktion aufrufen.

Referenz: 7.6.2.8/10 [expr.new]

Ein neuer Ausdruck kann Speicher für das Objekt erhalten, indem er eine Zuordnungsfunktion ( [basic.stc.dynamic.allocation]) aufruft . Wenn der neue Ausdruck durch Auslösen einer Ausnahme beendet wird, kann der Speicher durch Aufrufen einer Freigabefunktion freigegeben werden. Wenn der zugewiesene Typ ein Nicht-Array-Typ ist, lautet der Name der Zuordnungsfunktion operator newund der Name der Freigabefunktion operator delete. Wenn der zugewiesene Typ ein Array-Typ ist, lautet der Name der Zuordnungsfunktion operator new[]und der Name der Freigabefunktion operator delete[].


Betrachten Sie als Gegenbeispiel, dass wir beide definieren

T operator+(T, T);
void* T::operator new(std::size_t);

für einige Typ T dann Addition in jeder Form:

T a, b;
T c = a + b;
T d = T::operator +(a, b);

ist identisch. Die Infixnotation ist nur syntaktischer Zucker für den Operatoraufruf.

Die Zuordnung verhält sich jedoch ganz anders:

T *p = new T;
// does much more than
void *v = T::operator new(sizeof(T));

Daher ist es nicht sinnvoll, den syntaktischen Zucker mit dem neuen Ausdruck für einen Aufruf von aufzurufen operator new. Das newSchlüsselwort wählt also nicht einfach die aufzurufende Funktion aus. Es kann nicht sein, oder es müsste die operator deleteFunktion erwähnen , die auch aufgerufen werden könnte.

Nutzlos
quelle
2
" operator newIst ein überladbarer Betreiber" - oder?! Ich glaube nicht: operator + ist kein überladbarer Operator - +und Sie definieren Überladungen über eine aufgerufene Funktionoperator + .
Konrad Rudolph
1
Nein, ich habe darauf geantwortet, indem ich darauf hingewiesen habe, dass der Operator eine bestimmte Funktion ist, die als Teil des neuen Ausdrucks aufgerufen wird. Ein neuer Ausdruck ist ein Ausdruck, der durch ein Schlüsselwort identifiziert wird, und er findet einen geeigneten Operator zum Aufrufen.
Nutzlos
1
Ich sehe immer noch nicht, wie das den Status des newSchlüsselworts adressiert, wie es in einem neuen Ausdruck erscheint.
John Bollinger
5
In der Tat newlegt die Tatsache, dass der Operator überlastet ist, nahe, dass die Antwort ja sein sollte , new(selbst) ist ein Operator.
John Bollinger
2
Der Standard bezieht sich nur auf einen Ausdruck, der auch einen Operator aufruft. Sie können nicht dasselbe sein, ohne dass dies rekursiv ist. Die sparsame Interpretation lautet daher, dass der Ausdruck und der Operator genau und nur das sind, was der Standard sagt.
Nutzlos
11

Ich würde es nur als neuen Ausdruck bezeichnen , um Verwechslungen zu vermeiden, bei void* operator new ( std::size_t count )denen der neue Ausdruck nur als Teil des Prozesses zugewiesen wird (Zuordnungsspeicher, Startlebensdauer, aufrufender Konstruktor).

Das Problem dabei newist, dass es mehr als nur das Aufrufen des operator new. Welches ist ein bisschen verwirrend, weil für x + ydie +einzigen Anrufe operator +.

t.niese
quelle
9

Dies wird durch [expr.new] geregelt , das klar zwischen einem neuen Ausdruck und der Art und Weise unterscheidet, wie ein neuer Ausdruck durch Aufrufen einer Zuweisungsfunktion , die benannt wird , Speicherplatz erhält operator new. Insbesondere aus [expr.new] / 8 [ Schwerpunkt Mine]:

Ein neuer Ausdruck kann Speicher für das Objekt erhalten, indem er eine Zuordnungsfunktion ([basic.stc.dynamic.allocation]) aufruft. Wenn der neue Ausdruck durch Auslösen einer Ausnahme beendet wird, kann der Speicher durch Aufrufen einer Freigabefunktion freigegeben werden. Wenn der zugewiesene Typ ein Nicht-Array-Typ ist, lautet der Name der Zuordnungsfunktionoperator new und der Name der Freigabefunktion lautet Operator löschen. Wenn der zugewiesene Typ ein Array-Typ ist, lautet der Name der Zuordnungsfunktion Operatornew[] und der Name der Freigabefunktion Operator delete[].


Ist es richtig zu sagen, dass das Schlüsselwort, newwie es in einem neuen Ausdruck verwendet wird, ein Operator ist?

Insbesondere das Beispiel von [expr.new] / 4 , wenn auch nicht normativ, beschreibt diese Funktion als Operatorfunktion; "[...] der newBetreiber" :

[...] Stattdessen kann die explizit in Klammern gesetzte Version des neuen Operators verwendet werden, [...]

dfrib
quelle
3
Danke für die Antwort. Aus der Anzahl der Antworten, die ich erhalten habe, geht hervor, dass es möglicherweise keine strenge Sprache gibt, die diese Frage auf die eine oder andere Weise beantwortet. Nicht normativer Text könnte also der beste Beweis sein.
François Andrieux
7

Nein.

Nun, irgendwie ja, in dem Sinne , dass es Menschen gibt , die die Meinung newin new inteinem Operator sein. Diese Meinung steht jedoch (meistens) im Widerspruch zum Standard.

Zum einen [lex.operators/1]werden die Operatoren in der Sprache. Lassen Sie sich nicht täuschen, dass dies auch nur "Vorverarbeitungsoperatoren" sind. Eine solche Unterscheidung besteht nicht im Sinne von lexikalischen Operatoren. Es wäre auch nicht sinnvoll, da Sie (zum Beispiel) ++kein Makro können.

newist in der Tat ein Schlüsselwort (per [lex.key/1]).

Schauen wir uns als nächstes den neuen Ausdruck selbst an. Hier wird es etwas wolliger. Es gibt zum Beispiel den folgenden Wortlaut in [expr.new/4]:

Stattdessen kann die explizit in Klammern gesetzte Version des neuen Operators verwendet werden, um Objekte mit zusammengesetzten Typen zu erstellen

Ich halte dies für einen redaktionellen Fehler, da er im Widerspruch zu den oben angegebenen Definitionen steht und nirgendwo anders in diesem Abschnitt vorkommt.

Dann kommen wir zur Überlastung des Bedieners . In seiner grammatikalischen Erstellung für eine Operatordeklaration wird das Terminal, das Dinge (einschließlich new) auflistet, als Operator ( [over.oper.general/1]) bezeichnet. Ich glaube nicht, dass wir uns darüber Sorgen machen müssen. Die Namen von Terminals in der Grammatik sollten niemals Definitionen von Begriffen einführen. Schließlich haben Sie den Ausdruck, dass _ keine bitweise UND-Verknüpfung sein muss. es kann nur ein Gleichheitsausdruck sein :

und-Ausdruck :
   Gleichheitsausdruck
   und -ausdruck & Gleichheitsausdruck

Es ist üblich, Grammatiken wie diese zu definieren, und dies bedeutet sicherlich nicht, dass jeder Gleichheitsausdruck irgendwie als Aufruf des bitweisen AND-Operators zu betrachten ist.

Schließlich haben einige behauptet, dass der folgende Wortlaut (auch im Abschnitt zum Überladen von Operatoren) ein Beweis dafür newist, dass er jetzt irgendwie isoliert magisch ein Operator ist:

Die Betreiber new[], delete[], (), und []sind von mehr als einem Token gebildet

Ich sage ihnen, dass nicht nur newnicht einmal aufgeführt ist, sondern dass der Begriff "Operator" eindeutig im weiteren Sinne von "Dinge, die überladen werden können" verwendet wird, obwohl er newan sich immer noch kein Operator ist . Es ist auch in einer nicht normativen Notiz, die Ihnen alles sagen sollte, was Sie wissen müssen.

Und wie Sie selbst betonen, betrachten wir bereits operator newetwas anderes.

Asteroiden mit Flügeln
quelle
1
[lex.operators] ist eindeutig unvollständig (und soll nicht vollständig sein!), da [expr.sizeof] normativ sagt, dass dies auch sizeofein Operator ist. [expr.throw] ist in Bezug auf weniger explizit, throwspricht aber immer noch von einem „Operanden“ throw, was impliziert, dass throwes sich um einen Operator handelt.
Konrad Rudolph
6

Obwohl ich weiß, dass Sie nach einer semantischen Antwort suchen, würde ich meiner Meinung nach sagen, dass es sich um ein "Schlüsselwort" handelt (da es eindeutig reserviert ist), und ich gehe davon aus, dass wir beide wissen, dass es einfach das Konstrukt von C ++ für die Speicherzuweisung ist. Das heißt, wenn ich an die "Operatoren" von C ++ denke, denke ich eher an Funktionen mit einer festgelegten Eingabe / Ausgabe, die für bestimmte Typen überschrieben werden kann. new ist für alle Typen gleich (und verwirrender kann es überschrieben werden).

Ich bin mir nicht sicher, wie die offizielle Referenz ist, aber:

Der neue Ausdruck ordnet Speicher zu, indem die entsprechende Zuordnungsfunktion aufgerufen wird. Wenn type ein Nicht-Array-Typ ist, lautet der Name der Funktion operator new. Wenn type ein Array-Typ ist, lautet der Name der Funktion operator new []

https://en.cppreference.com/w/cpp/language/new

Es scheint dann zu folgen, dass dies new <type>ein Ausdruck zum Zuweisen von Speicher ist, während newder Operator für diesen Ausdruck ist.

Mit der gleichen Logik:

  • sizeofist ein "Operator" für den Ausdruck sizeof(<type>)(obwohl sizeofes sich um einen Operator zur Kompilierungszeit handelt, der sich ein wenig von dem unterscheidet, was wir gewohnt sind)
  • + ist ein Operator für einen Ausdruck <type> <operator> <type>
  • throw ist ein Operator für den Ausdruck throw <throwaable>
Schurke
quelle
Ist nach dieser Logik []()auch ein Operator? Ist for? Ist throw?
Konrad Rudolph
1
@KonradRudolph Ja, ich würde sagen []und ()separate Betreiber bilden. Wieder forist absolut ein Schlüsselwort, aber wo ich als Operator beschreiben würde, war der erste Teil der Möglichkeit, überschrieben zu werden. Technisch durch , dass sizeofkein Betreiber, das gilt für C ++, dass es eher eine Vorverarbeitung Ausdruck ist. Und throwist ein Operator eines Ausdrucksthrow <throwable>
Rogue
Ich meinte speziell []()in Kombination, wenn ich ein Lambda definiere. Ihre Antwort ist aber auch interessant, weil (in C ++) die Antwort vom Kontext abhängt: in foo(), ()ist ein (überladbarer!) Operator; in (1 + 2)es keinen Operator überhaupt ist (in einigen anderen Sprachen, insbesondere R, das ist anders). Auf jeden Fall reicht das überschreibbare Kriterium nicht aus. Es gibt viele Dinge in C ++ , die eindeutig Betreiber trotz nicht überladbaren sind ( ., ::, :?, beide sizeof s, etc).
Konrad Rudolph
1
Ah, []()als Lambda ist es schwierig, es zu definieren (insbesondere, weil ich mit meinem C ++ nicht so auf dem neuesten Stand bin). Hier würde ich also immer noch sagen , dass sie [] ()verschiedene Operatoren eines Lambda- Ausdrucks darstellen , aber ich bin mir nicht sicher, ob Sie argumentieren würden, dass sie nicht überschrieben werden können, oder ob die bloße Implementierung / Deklaration eines Lambdas das Überschreiben des grundlegenden Lambdas darstellt (wie z in Java). Sprachdesign wird dort zu einer Kunst über der Wissenschaft. Soweit ( ... )es ein Trennzeichen in den meisten langs ist, die ich verwendet habe, aber ich werde R ganz schnell genauer betrachten
Rogue
2
Nebenbei bemerkt, in R ist alles eine Funktion und alles kann neu definiert werden. Es gibt keine umfassende normative Referenz und ich bin nicht ganz sicher, ob Klammern als Operatoren betrachtet werden, aber sie können neu definiert werden. Tatsächlich ist der Ausdruck (a + b)semantisch identisch mit dem Funktionsaufruf "(" (a + b)) oder "(" ("+" (a, b))), wobei "x" verwendet werden kann, um einen Namen zu erstellen xsyntaktisch eher einem Funktionsaufruf als einem speziellen entsprechen (z. B. einem Infix-Operator).
Konrad Rudolph