84

The expression new int; such as in int * x = new int; is a new expression. The term "new operator" seems to be used interchangeably with "new expression", for example in this question : Difference between 'new operator' and 'operator new'?

Is it correct to say that the keyword new as it is used in a new expression is an operator? Why or why not?

If not, is there another justification for calling a new expression "new operator"?

I am having trouble finding an authoritative definition for what constitutes an operator.

I already understand the distinction between operator new which allocates memory for an object and "new expression" which may eventually call an operator new.

François Andrieux
  • 24,129
  • 6
  • 46
  • 72
  • 4
    @Rogue - Thing is, `new` is like `sizeof` here. And I think the majority of the C++ community thinks of `sizeof` as an operator. The stansard even refers to the "`sizeof` operator" when describing its effects. – StoryTeller - Unslander Monica Oct 20 '20 at 15:32
  • 2
    @StoryTeller-UnslanderMonica so continuing from my second comment (now moved to an answer), with `sizeof`, I'd say that would be the operator of an expression `sizeof()`. And `+` is an operator for a unary expression ` `. That's my takeaway/interpretation at least, feel free to correct me on it. – Rogue Oct 20 '20 at 15:33
  • 2
    @Rogue - Indeed. Which is why I'd argue the normative text is rather arbitrary when refferring to one as an operator while not to the other. – StoryTeller - Unslander Monica Oct 20 '20 at 15:35
  • 1
    A side note to the accepted answer: regardless of whether `new` is an operator or not, there's a difference between an *expression* and and an operator. E.g., `new int` is an expression as it evaluates to something. If `new` is considered an operator, then only the "new" part of `new int` is the operator (i.e., it's its own separate thing). Conceptually, an operator is something that acts on something else. – Filip Milovanović Oct 22 '20 at 18:31

6 Answers6

141

new in new int is not considered to be an operator. It is also not considered to be not an operator.

The C++ standard is really vague, and even inconsistent, about what constitutes an 'operator'. When listing operators (as defined during lexing and preprocessing), it lists them along with "punctuators" (things like (), but never really gives any rules for punctuators in general. It lists new as both a keyword and an operator. It lists sizeof in the set of keywords but NOT in the set of operators, but later refers to it as an operator.

The takeaway here is that the C++ standards committee is not overly concerned with separating the lexical world into "operators" and "non-operators". This is because there isn't really any need to. There's no grammatical rules which apply to all operators or all non-operators. Important sets, like the set of overloadable operators, are given separately; grammatical rules for things like binary arithmetic expressions are given one at a time.

Basically, "operator" is not a category which is formally meaningful to the C++ language, so any categorical answer is going to be based on how it "feels". You can call it an operator if you like, but you can also call it a keyword (or a punctuator!) and the language standard will not disagree with you.

Sneftel
  • 34,359
  • 11
  • 60
  • 94
  • 6
    Both the C and C++ Standards are sloppy with regard to a lot of their terminology, since they expected that readers would infer what was meant if there were gaps or ambiguities, rather than trying to niggle over whether they could use such omissions to justify "optimizations" in cases the authors of the Standards would have thought sufficiently absurd that there was no need to expressly forbid them. – supercat Oct 22 '20 at 22:03
  • The standard may be vague in human descriptions that way, but there is the keyword `operator` and I'd imagine that, when someone asks for an exact delineation, it's fair to use the English word "operator" for things that work with that keyword. In that sense, `new`, `new[]`, `delete`, `delete[]`, `co_await`, some typecasts, and conversions of user-defined literals to objects would be operators. – hemflit Nov 18 '20 at 16:57
  • @hemflit operators predate the `operator` keyword, and include things like `.` which can't be used with the `operator` keyword. If I were forced at gunpoint to come up with a definition of "operator", my mind would not go to "overloadable operator". – Sneftel Nov 18 '20 at 16:59
  • @Sneftel use of the ambiguous English word "operator" predates the `operator` keyword, yes. If I were forced to come up with an absolutely precise delineation of what is or isn't an operator, I'd go with the one thing that's precisely defined in the grammar. In everyday communication, I wouldn't need that much precision all the time. – hemflit Nov 19 '20 at 20:48
  • I’ll readily concede that it’s a precise definition. It’s just not a good one. – Sneftel Nov 19 '20 at 21:32
16

Is it correct to say that the keyword new as it is used in a new-expression is an operator? Why or why not?

No. The new in a new-expression is a keyword identifying a new-expression.

A new-expression calls an operator new or operator new[] to get storage. It also initializes that storage, and de-allocates it (with operator delete or operator delete[]) if the initialization throws.

There's a clear distinction, in that operator new is only referred to as a overloadable user-replaceable function, and a new-expression does more than just call this function.

Reference: 7.6.2.8/10 [expr.new]

A new-expression may obtain storage for the object by calling an allocation function ([basic.stc.dynamic.allocation]). If the new-expression terminates by throwing an exception, it may release storage by calling a deallocation function. If the allocated type is a non-array type, the allocation function's name is operator new and the deallocation function's name is operator delete. If the allocated type is an array type, the allocation function's name is operator new[] and the deallocation function's name is operator delete[].


Consider by way of counterexample, that we define both

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

for some type T, then addition in either form:

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

is identical. The infix notation is just syntactic sugar for the operator call.

Allocation however, behaves very differently:

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

so it's not reasonable to call the new-expression syntactic sugar for a call to operator new. Thus, the new keyword isn't simply selecting the function to call. It can't be, or it would have to mention the operator delete function that might also be called.

Useless
  • 55,472
  • 5
  • 73
  • 117
  • 2
    “`operator new` is an overloadable operator” — is it?! I don’t think so: `operator +` *isn’t* an overloadable operator — `+` is, and you define overloads via a *function* called `operator +`. – Konrad Rudolph Oct 20 '20 at 15:46
  • You can provide class-specific versions, so _effectively_, even if the resolution mechanism is different. I'll clarify. – Useless Oct 20 '20 at 15:49
  • You respond to the OP's question about whether the `new` keyword *in* a new-expression is considered an operator with an argument that an overall new-expression is not an operator. – John Bollinger Oct 20 '20 at 15:49
  • 1
    No, I answered it by pointing out that the operator is a specific function called as part of the new-expression. A new-expression is an expression identified by a keyword, and it finds a suitable operator to call. – Useless Oct 20 '20 at 15:51
  • 1
    I'm still not seeing how that addresses the status of the `new` keyword as it appears in a new-expression. – John Bollinger Oct 20 '20 at 15:53
  • Thanks for your answer. While I am aware that `operator new` exists and that it can be easily confused with a "new expression" I'm not sure that the existence of `operator new` precludes that `new` in a "new expression" is also considered an operator. It only provides an explanation as to why it might be erroneously called operator if it is not an operator. – François Andrieux Oct 20 '20 at 15:53
  • 6
    Indeed, the fact that `new` is subject to operator overloading suggests that the answer should be ***yes***, `new` (itself) is an operator. – John Bollinger Oct 20 '20 at 15:55
  • 2
    The standard refers only to an expression that also calls an operator. They can't be the same thing without that being recursive, so the parsimonious interpretation is that the expression and the operator are exactly and only what the standard says they are. – Useless Oct 20 '20 at 15:55
  • @John I think the code samples in the answer show that the "new" in a *new-expression* is not an operator. The operator is that which you can user-define, which has a distinct, different meaning (it only allocates untyped memory). If it is an operator you can call it with `operator x()`. – Peter - Reinstate Monica Oct 23 '20 at 15:12
12

I would only call it new expression to avoid confusion with void* operator new ( std::size_t count ) which only allocates memory as part of the process the new expression invoices (allocation memory, starting lifetime, calling constructor).

The problem with new is that it does more than just calling the operator new. Which is a bit confusing because for x + y the + only calls operator +.

t.niese
  • 32,069
  • 7
  • 56
  • 86
9

This is governed by [expr.new], which clearly differentiates between a new-expression and how a new expression may obtain storage by means of calling an allocation function, which is named operator new. Particularly, from [expr.new]/8 [emphasis mine]:

A new-expression may obtain storage for the object by calling an allocation function ([basic.stc.dynamic.allocation]). If the new-expression terminates by throwing an exception, it may release storage by calling a deallocation function. If the allocated type is a non-array type, the allocation function's name is operator new and the deallocation function's name is operator delete. If the allocated type is an array type, the allocation function's name is operator new[] and the deallocation function's name is operator delete[].


Is it correct to say that the keyword new as it is used in a new expression is an operator?

Particularly, the example, albeit non-normative, of [expr.new]/4 describe this function as an operator function; "[...] the new operator":

[...] Instead, the explicitly parenthesized version of the new operator can be used [...]

dfrib
  • 56,823
  • 7
  • 97
  • 157
  • 3
    Thanks for the answer. From the number of answers I've received, it's starting to look like there might not be strict language that answers this question, one way or another. So non-normative text might end up being the best evidence. – François Andrieux Oct 20 '20 at 15:55
8

No.

Well, sort of yes, in the sense that there exist people who consider new in new int to be an operator. However, this opinion is (mostly) at odds with the standard.

Firstly, [lex.operators/1] lists the operators in the language. Don't be fooled into thinking that these are just "preprocessing operators", either; no such distinction exists in the sense of lexical operators. It wouldn't make sense, either, since you cannot (for example) ++ a macro.

new is, in fact, a keyword (per [lex.key/1]).

Next, let's look at new-expression itself. This is where things get a little more wooly. There is, for example, the following wording in [expr.new/4]:

Instead, the explicitly parenthesized version of the new operator can be used to create objects of compound types

I consider this to be an editorial error, since it is at odds with the definitions provided above, and does not occur anywhere else in that section.

Then we come to operator overloading. In its grammatical production for an operator declaration, the terminal listing things (including new) is named operator ([over.oper.general/1]). I don't think we need to worry about this. The names of terminals in the grammar have never been intended to introduce definitions of terms. After all, you have and-expression that _doesn't need to be a bitwise AND operation; it can just be an equality-expression:

and-expression:
   equality-expression
   and-expression & equality-expression

It's common to define grammars like this, and it certainly doesn't mean that every equality-expression is somehow to be considered an invocation of the bitwise AND operator.

Finally, some have claimed that the following wording (also in the operator overloading section) is proof that new is somehow now, in isolation, magically an operator:

The operators new[], delete[], (), and [] are formed from more than one token

To them I say, not only is new not even listed, but this is clearly using the term "operator" in the more broad sense of "things that can be overloaded", even though new in itself is still not an operator. It's also in a non-normative note, which should tell you all you need to know.

And, as you point out yourself, we already consider operator new to be something else.

Asteroids With Wings
  • 16,164
  • 2
  • 17
  • 33
  • 1
    [lex.operators] is clearly incomplete (and not meant to be complete!), since [expr.sizeof] normatively says that `sizeof` is an operator, too. [expr.throw] is less explicit with regards to `throw` but it still talks of an “operand” to `throw`, which implies that `throw` is an operator. – Konrad Rudolph Oct 20 '20 at 16:17
7

While I know you're looking for a semantical answer, as far as opinion I would say it's a "keyword" (as it's clearly reserved), and I assume we both know that it's simply C++'s construct for memory allocation. That said, when I think of C++'s "operator"s, I tend to think of functions with a set input/output that can be overriden for specific types. new is the same for all types (and more confusingly it can be overridden).

Not sure how official cppreference is, but:

The new-expression allocates storage by calling the appropriate allocation function. If type is a non-array type, the name of the function is operator new. If type is an array type, the name of the function is operator new[]

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

It seems to follow then that new <type> is an expression to allocate memory, while new is the operator for that expression.

Using that same logic:

  • sizeof is an "operator" for the expression sizeof(<type>) (though sizeof is a "compile-time" operator, a bit different than what we're used to)
  • + is an operator for an expression <type> <operator> <type>
  • throw is an operator for the expression throw <throwaable>
Rogue
  • 9,871
  • 4
  • 37
  • 66
  • By that logic, is `[]()` also an operator? Is `for`? Is `throw`? – Konrad Rudolph Oct 20 '20 at 15:37
  • 1
    @KonradRudolph yeah I would say `[]` and `()` constitute separate operators. Again `for` is absolutely a keyword, but where I would delinate being an operator was that first part of being able to be overridden. _Technically_ by that, `sizeof` isn't an operator, which is true of C++ in that it's more of a preprocessing expression. And `throw` is an operator of an expression `throw ` – Rogue Oct 20 '20 at 15:40
  • I specifically meant `[]()` in combination when defining a lambda. But your reply is also interesting because (in C++) the answer depends on the context: in `foo()`, `()` is an (overloadable!) operator; in `(1 + 2)` it isn’t an operator at all (in some other languages, notably R, this is different). Anyway, the overridable criterion isn’t enough. There are plenty of things in C++ that are unambiguously operators despite not being overloadable (`.`, `::`, `:?`, *both* `sizeof`s, etc). – Konrad Rudolph Oct 20 '20 at 15:43
  • 1
    Ah, `[]()` as a _lambda_ is a tricky beast to define (specifically because I'm not as up to speed on my C++). So here I would still say `[]` `()` constitute different operators of a lambda _expression_, but I'm not sure whether you would argue that they can't be overridden, or if the very act of implementing/declaring a lambda constitutes overriding the basic lambda (like in Java). Language design starts becoming a bit of an art over science there. As far as `( ... )`, it's a separator in most langs I've used, but I'll take a gander at R real quick – Rogue Oct 20 '20 at 15:50
  • “though `sizeof` is not officially an operator!” — No, it definitely is an official operator ([expr.sizeof]/1). – Konrad Rudolph Oct 20 '20 at 15:51
  • You're right on `sizeof`, fixed that. For `R`, it seems it evaluates `(a...b)` parenthetical expressions as a function of `a...b` with an output of what they evaluate to? Again I would say some languages don't make the distinction of that being an operator since it doesn't really need to differ amongst any type in the system. – Rogue Oct 20 '20 at 15:54
  • 2
    As a side note, in R everything is a function and *everything* can be redefined. There’s no comprehensive normative reference and I’m not entirely sure parentheses are considered operators but they can be redefined; in fact, the expression `(a + b)` is semantically identical to the function call \`(\`(a + b), or, indeed, \`(\`(\`+\`(a, b)), where \`x\` can be used to make a name `x` syntactically conform to a function call rather than special (such as an infix operator). – Konrad Rudolph Oct 20 '20 at 15:59