`new int;` 中的 `new` 是否被视为运算符?

Fra*_*eux 84 c++ language-lawyer

new int;诸如 in 之类的表达式int * x = new int;是一个新表达式。术语“新运算符”似乎可以与“新表达式”互换使用,例如在这个问题中:“新运算符”和“运算符新”之间的区别?

new在 new 表达式中使用的关键字是运算符是否正确?为什么或者为什么不?

如果不是,是否还有另一个理由将新表达式称为“新运算符”?

我无法找到构成运算符的权威定义。

我已经理解为对象分配内存的运算符 new和最终可能调用operator new.

Sne*_*tel 141

newinnew int不被视为运算符。它也不被视为不是运营商。

C++ 标准对于“运算符”的构成非常模糊,甚至不一致。当列出运算符(在词法分析和预处理期间定义)时,它会将它们与“标点符号”(例如()一起列出,但通常从未真正给出任何标点符号规则。它new同时作为关键字和运算符列出。它列sizeof在关键字集中但不在运算符集中,但后来将其称为运算符。

这里的要点是 C++ 标准委员会并没有过度关注将词汇世界分为“操作符”和“非操作符”。这是因为真的没有任何必要。没有适用于所有运算符或所有非运算符的语法规则。重要的集合,如可重载运算符的集合,是单独给出的;一次给出一个诸如二进制算术表达式之类的语法规则。

基本上,“运算符”不是对 C++ 语言具有正式意义的类别,因此任何分类答案都将基于它的“感觉”。如果您愿意,您可以将其称为运算符,但您也可以将其称为关键字(或标点符号!),语言标准不会与您不一致。

  • C 和 C++ 标准在许多术语方面都很草率,因为他们期望读者在存在间隙或歧义时推断出其含义,而不是试图纠结是否可以使用此类遗漏来证明“优化”的合理性。 “在某些情况下,标准的作者会认为非常荒谬,没有必要明确禁止它们。 (6认同)

Use*_*ess 16

newnew 表达式中使用的关键字是运算符是否正确?为什么或者为什么不?

号的new在一个新的表达式是识别关键字新表达

一个新的表达 要求operator newoperator new[]获得存储。它还初始化该存储,并在初始化抛出时取消分配它(使用operator deleteoperator delete[])。

有一个明显的区别,它operator new仅被称为可重载的用户可替换函数,而new 表达式不仅仅调用此函数。

参考:7.6.2.8/10 [expr.new]

新表达可以通过调用分配函数获得用于对象存储([basic.stc.dynamic.allocation])。如果new 表达式因抛出异常而终止,则它可以通过调用释放函数来释放存储空间。如果分配的类型是非数组类型,则分配函数的名称为operator new,释放函数的名称为operator delete。如果分配的类型是数组类型,则分配函数的名称为operator new[],释放函数的名称为operator delete[]


通过反例考虑,我们定义了两者

T operator+(T, T);
void* T::operator new(std::size_t);
Run Code Online (Sandbox Code Playgroud)

对于某些类型 T,然后以任一形式添加:

T a, b;
T c = a + b;
T d = T::operator +(a, b);
Run Code Online (Sandbox Code Playgroud)

是相同的。中缀符号只是操作符调用的语法糖。

然而,分配的行为非常不同:

T *p = new T;
// does much more than
void *v = T::operator new(sizeof(T));
Run Code Online (Sandbox Code Playgroud)

所以调用new-expression语法糖来调用operator new. 因此,new关键字不是简单地选择要调用的函数。它不能,或者它必须提到operator delete也可能被调用的函数。

  • 事实上,“new”受运算符重载影响的事实表明答案应该是***是***,“new”(本身)是一个运算符。 (6认同)
  • “`operator new` 是一个可重载的运算符”——是吗?!我不这么认为:`operator +` *不是*可重载的运算符 - `+` 是,并且您可以通过称为 `operator +` 的 *函数* 定义重载。 (2认同)
  • 该标准仅涉及也调用运算符的表达式。如果没有递归,它们就不可能是同一件事,因此简约的解释是表达式和​​运算符与标准所说的完全相同。 (2认同)

t.n*_*ese 12

我只会称它为新表达式以避免混淆void* operator new ( std::size_t count ),它只在新表达式 发票过程中分配内存(分配内存、起始生命周期、调用构造函数)。

问题new在于它不仅仅是调用operator new. 这是一个有点混乱,因为x + y+只有通话operator +


dfr*_*fri 9

这是由[expr.new] 控制的,它清楚地区分了new 表达式和 new 表达式如何通过调用名为的分配函数来获取存储空间operator new。特别是,来自 [expr.new]/8 [强调我的]:

新表达式可以得到存储通过调用分配函数为对象([basic.stc.dynamic.allocation])。如果 new 表达式因抛出异常而终止,则它可以通过调用释放函数来释放存储空间。如果分配的类型是非数组类型,则分配函数的名称是operator new,释放函数的名称是 operator delete。如果分配的类型是数组类型,则分配函数的名称为 operatornew[],释放函数的名称为 operator delete[]


new在 new 表达式中使用的关键字是运算符是否正确?

特别是,[expr.new]/4的示例虽然不规范,但将该函数描述为运算符函数; “[...]new操作员”

[...] 相反,可以使用新运算符的显式括号版本 [...]

  • 感谢你的回答。从我收到的答案数量来看,似乎可能没有严格的语言以某种方式回答这个问题。因此,非规范性文本可能最终成为最好的证据。 (3认同)

Ast*_*ngs 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

我对他们说,不仅new没有列出,而且这显然是在更广泛的意义上使用“运算符”一词,即“可以重载的事物”,即使new其本身仍然不是运算符。它也在一个非规范性的注释中,它应该告诉你所有你需要知道的。

而且,正如您自己指出的那样,我们已经考虑operator new成为其他东西。

  • [lex.operators] 显然是不完整的(并且并不意味着完整!),因为 [expr.sizeof] 规范地表示 `sizeof` 也是一个运算符。[expr.throw] 对于 `throw` 不太明确,但它仍然谈到了 `throw` 的“操作数”,这意味着 `throw` 是一个运算符。 (2认同)

Rog*_*gue 7

虽然我知道您正在寻找语义答案,但就意见而言,我会说它是一个“关键字”(因为它显然是保留的),并且我假设我们都知道它只是 C++ 的内存分配构造。也就是说,当我想到 C++ 的“操作符”时,我倾向于想到具有可以为特定类型覆盖的一组输入/输出的函数。new 对所有类型都是相同的(更令人困惑的是它可以被覆盖)。

不确定 cppreference 的官方如何,但是:

new 表达式通过调用适当的分配函数来分配存储。如果 type 是非数组类型,则函数名称为 operator new。如果 type 是数组类型,则函数名是 operator new[]

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

似乎接着 thatnew <type>是分配内存的表达式,而new是该表达式的运算符。

使用相同的逻辑:

  • sizeof是表达式的“运算符” sizeof(<type>)(虽然sizeof是“编译时”运算符,与我们习惯的有点不同)
  • + 是表达式的运算符 <type> <operator> <type>
  • throw 是表达式的运算符 throw <throwaable>

  • 附带说明一下,在 R 中,一切都是函数,并且*一切*都可以重新定义。没有全面的规范参考,我不完全确定括号是否被视为运算符,但可以重新定义它们;事实上,表达式 `(a + b)` 在语义上与函数调用 \`(\`(a + b) 相同,或者实际上, \`(\`(\`+\`(a, b) ),其中 \`x\` 可用于使名称 `x` 在语法上符合函数调用而不是特殊的(例如中缀运算符)。 (2认同)