New‘ in‘ new int;’是算子吗?

int * x = new int;这样的表达式 new int;新的表达方式。术语“新操作符”似乎可以与“新表达式”交替使用,例如在这个问题中: “新操作员”和“新操作员”之间的区别?

在新表达式中使用的关键字 new是一个运算符,这样说对吗?为什么?

如果没有,是否还有其他理由调用一个新的表达式“ new 运算符”?

我很难找到一个权威的定义,什么构成了一个经营者。

我已经理解了为对象分配内存的 新来的接线员和最终可能调用 operator new的“新表达式”之间的区别。

8448 次浏览

虽然我知道你正在寻找一个语义上的答案,但就我的观点而言,我会说它是一个“关键字”(因为它显然是保留的) ,我想我们都知道,它只是 C + + 的内存分配结构。也就是说,当我考虑 C + + 的“操作符”时,我倾向于考虑那些具有可以为特定类型重写的集合输入/输出的函数。New 对于所有类型都是相同的(更令人困惑的是,它可以被重写)。

我不知道官方的首选方案是什么,但是:

New-expression 通过调用适当的分配函数来分配存储。如果 type 是非数组类型,则函数的名称是运算符 new。如果 type 是数组类型,则函数的名称为运算符 new []

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

这样看来,new <type>是一个分配内存的表达式,而 new是该表达式的操作符。

用同样的逻辑:

  • sizeof是表达式 sizeof(<type>)的“操作符”(尽管 sizeof是“编译时”操作符,与我们以前使用的操作符略有不同)
  • +是表达式 <type> <operator> <type>的运算符
  • throw是表达式 throw <throwaable>的运算符

我只称它为 新的表达方式,以避免与 void* operator new ( std::size_t count )混淆,void* operator new ( std::size_t count )只将内存分配作为 新的表达方式发票(分配内存、开始生存期、调用构造函数)进程的一部分。

new的问题在于它不仅仅是调用 operator new。这有点令人困惑,因为对于 x + y+只调用 operator +

新表达式中使用的关键字 new是一个操作符,这样说对吗?为什么?

不,新表达式中的 new是标识 新表达式的关键字。

一个 新表达式 电话一个 operator newoperator new[]来获得存储。它还初始化该存储,并在初始化抛出时解除它的分配(使用 operator deleteoperator delete[])。

这里有一个明显的区别,即 operator new仅被称为 超载用户可替换函数,而 新表达式不仅仅是调用这个函数。

参考文献: 7.6.2.8/10 [expr.new]

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


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

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

对于某种类型的 T,然后以任意一种形式加上:

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

中缀符号只是接线员调用的语法糖。

然而,资源配置的表现却截然不同:

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

因此,为了调用 operator new而调用 新表达式语法 Sugar 是不合理的。因此,new关键字不仅仅是选择要调用的函数。这是不可能的,否则它将不得不提到也可能被调用的 operator delete函数。

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

新表达式可以通过调用分配函数([ basic.stc.Dynamic.distribution ])获得对象的存储 。如果新表达式通过引发异常而终止,它可能通过调用释放函数来释放存储。如果分配的类型是非数组类型,则 分配函数的名称是 operator new和释放函数的名称为运算符 delete。如果分配的类型是数组类型,则 分配函数的名称是操作符 new[]和释放函数的名称为操作符 delete[]


在一个新表达式中使用的关键字 new是否是一个运算符?

特别是,[ expr.new ]/4的例子虽然不规范,但是将这个函数描述为一个操作函数; new操作员”:

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

没有。

嗯,是的,在某种意义上,有人认为 new int中的 new是一个操作符。然而,这个观点(大部分)与标准不一致。

首先,[lex.operators/1]列出了语言中的运算符。也不要误以为这些只是“预处理操作符”; 在 词汇操作符的意义上并不存在这样的区别。这也没有意义,因为您不能(例如) ++宏。

事实上,new关键词(每个 [lex.key/1])。

接下来,让我们看看 新表达式本身。这就是事情变得有点模糊的地方。例如,在 [expr.new/4]中有以下措辞:

相反,新运算符的显式括号版本可用于创建复合类型的对象

我认为这是一个编辑错误,因为它与上面提供的定义不一致,并且不会出现在该部分的任何其他地方。

然后我们来到 运算符重载。在操作符声明的语法生成中,列出事物(包括 new)的终端命名为 接线员([over.oper.general/1])。我觉得我们不用担心这个。文法中的终端名称从来都不是为了引入术语的定义。毕竟,您有 和-表达,它 _ 不需要是位 AND 操作; 它可以只是一个 < em > 等式表达式 :

及-表达 :
< em > 相等-表达式
等式表达式

像这样定义语法是很常见的,当然这并不意味着每个 平等-表达都被认为是位 AND 操作符的调用。

最后,一些人声称,下面的措辞(也在运算符重载部分)证明了 new现在以某种方式孤立地奇迹般地成为了一个操作符:

操作符 new[]delete[]()[]由多个令牌组成

我对他们说,不仅是 new甚至没有列出,但这显然是使用术语“操作员”在更广泛的意义上的“事情,可以超载”,即使 new本身 仍然不是操作员。这也是一个非规范的说明,这应该告诉你所有你需要知道的。

而且,正如你自己指出的,我们已经认为 operator new是别的东西。

new int中的 new不被认为是操作符。它也不被认为是 没有操作符。

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

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

基本上,“操作符”不是一个对 C + + 语言有正式意义的范畴,所以任何范畴性的回答都将基于它的“感觉”。你可以称它为一个操作符,如果你喜欢,但你也可以称它为一个关键字(或标点符号!)而且语言标准也不会反对你。