C++ 为什么不是';t运算符new被迫将参数视为;常数大小;?

C++ 为什么不是';t运算符new被迫将参数视为;常数大小;?,c++,language-lawyer,new-operator,C++,Language Lawyer,New Operator,没有在任何地方使用下面的东西,但这个问题仍然在我的脑海里很久了 void* operator new (size_t size) { // distort `size` to other value return malloc(size); } 知道了以上可能不是重载的new的定义良好的行为(比如如果size减小),为什么标准编译器不强制它成为void*操作符new(const size\t) 对于运算符删除也有同样的理由,它应该作废运算符删除(void*const)(添加常量,以避免

没有在任何地方使用下面的东西,但这个问题仍然在我的脑海里很久了

void* operator new (size_t size)
{
  // distort `size` to other value
  return malloc(size);
}
知道了以上可能不是重载的
new
的定义良好的行为(比如如果
size
减小),为什么标准编译器不强制它成为
void*操作符new(const size\t)


对于
运算符删除
也有同样的理由,它应该
作废运算符删除(void*const)
(添加
常量
,以避免指针被更改)。

非引用参数的常量只具有次要意义

这些标准从调用者的角度定义了“重要”的事情

这些按值参数的常量不会也不能更改使用它们的任何代码。实施者可以照顾自己

更新:如果您愿意,可以这样写。

int f (const int);
int f (int) {return 0;}

int main () {
    int i;
    f (i);
}
我在上面没有发现任何错误。继续,并确定您的尺码(t:-)


预计会有异议:这里的
f
代表
新操作员
或其他什么。因此,我们有一个相互矛盾的声明/定义,但编译器没有抱怨。为什么?因为这无关紧要。

好吧,让我们假设它是常量

void* operator new (const size_t size)
{
   size_t alteredSize = size;
   alteredSize += 10; // for whatever reason
   return malloc( alteredSize );
}
这和

void* operator new (size_t size)
{
   size += 10;
   return malloc( size );
}
const
对复制到函数中的参数(按值传递)不强制使用该值-函数可以创建可写副本并更改该副本

void* operator new (const size_t n);
void* operator new (size_t n);
这两个是
运算符new
的完全相同的声明。唯一的区别是,如果它是一个定义,那么n将被允许或不被允许在函数体内部修改(这与调用方无关,因为参数是按值传递的)。因为这是一个实现细节,所以标准没有讨论它


记住,顶级常量在函数声明中被忽略。它们仅在定义上相关。

在这两种情况下,
const std::size\t
和plain
std::size\t
的参数类型都是
std::size\t
。该标准规定,当处理声明(后面的定义)中的函数签名时,
const
从类型中删除。具体 第8.3.5/3节:

[…]生成参数类型列表后,对这些类型进行若干转换以确定函数类型。任何修改参数类型的cv限定符都将被删除。[示例:类型void()(const int)变为void()(int)-结束示例]


现在,在函数的定义中,
const
确实具有您建议的效果:阻止您修改参数。您可以使用
const std::size\u t
参数自由实现
运算符new
。另一方面,强制执行基本上是无用的。正如其他人所提到的,可以通过将参数复制到另一个变量并使用该变量来颠覆参数为const的事实。如果编译器没有为语言增加真正的价值,那么就没有必要给编译器增加额外的验证负担。

您已经在
操作符new
上收到了许多很好的答案。另一个不将
size
参数设置为
运算符new
const的参数:重写实现可能希望分配比请求的空间更多的空间,例如cookie、保护字等

对于运算符delete也可以这样说,它应该使运算符delete无效(void*const);(添加常量以避免指针被更改)


在大多数使用虚拟内存的现代操作系统上,
free
不一定会将分配的内存释放给操作系统。内存可能仍然在程序的虚拟空间中。迂腐的重写器很可能希望在删除指向内存之前用绝对垃圾填充该内存,从而进一步使调用函数随后对该内存的使用无效。调用函数在删除指向内存后不得使用该内存,因此为什么要使用不必要的限制来阻碍
操作符的删除呢?

否,这与编译时检查有关。例如,您
返回0来自
操作员新建
和编译器警告您。你所说的只是拍你的脚之类的例子。你不允许更改
常量大小。您展示的第二个示例代码格式不正确。@Johannes Schaub-litb:我不明白。为什么它在那里?我不明白。那是康斯特,因为你让它康斯特。你能详细说明你的问题是什么吗?因为在编辑之前,你的第二个定义看起来像
操作符new(const size\u t size)然后你做了
size+=10但是规范规定“第一个参数的类型应为std::size_t(18.2)。”。这似乎禁止了
常量大小\u t
。它没有说参数类型列表或其签名应具有类型为
size\t
的第一个参数。这对我来说是模棱两可的:人们可以将其解释为允许
size\t
,但也可以将其解释为不允许。不过,我倾向于将其解释为允许
const size\u t
。我同意。但我看到,大多数时候编译器也关心琐碎的事情。我发现
const size\u t
微不足道。我不确定我是否完全理解您的意思,但在我看来,在这种情况下,歧义并不重要——从调用方的角度来看,它们是等价的和可互换的。Qui-bono?该标准规定,特定的
常量
不是函数签名的一部分(在声明中)。根据§8.3.5/3:生成参数类型列表后,对这些类型进行若干转换以确定函数类型。任何修改参数类型的cv限定符都将被删除。[E]