“sizeof new int;”是未定义行为吗?

32

代码:

#include<iostream>

using namespace std;

int main() 
{
    size_t i = sizeof new int;

    cout<<i;
}

在GCC编译器中,代码可以正常运行且没有任何警告或错误,并打印输出8

但是,在clang编译器中,我收到了以下警告:

warning: expression with side effects has no effect in an unevaluated context [-Wunevaluated-expression]
    size_t i = sizeof new int;
  • 哪个是正确的?
  • sizeof new int; 是未定义行为吗?

18
我看不出任何问题。这个警告更像是一种提醒,一切都在这里明确定义了。 - YSC
3
这个问题与C语言的为什么sizeof(x++)不会增加x的值?有关,但在C++中更加清晰。 - Bartek Banachewicz
@BartekBanachewicz - 在C语言中,更接近的等效方法是 sizeof malloc(some_value),它不会调用 malloc() 函数,并且如果在 #include <stdlib.h> 之后执行,则会得到与 sizeof(void *) 相等的结果。 - Peter
23
有人可能会认为编译器关心的是 WTF (令人困惑) 因素。 - luk32
2个回答

61
警告并未说明这是未定义行为,只是说使用的上下文,即 sizeof 不会触发副作用(new 的情况下是分配内存)。

[expr.sizeof] sizeof 运算符返回其操作数类型的非重叠对象占用的字节数。 操作数可以是表达式(未求值的操作数[expr.prop])或带圆括号的类型标识符。

标准还有助于解释其含义:

[expr.context] (...) 未求值的操作数不会被求值。

这是一种很好的方法来编写 sizeof(int*),虽然有点奇怪。


这很奇怪,但也不是那么奇怪。使用表达式而不是类型的愿望可能是DRY的一个案例。事实上,在C语言中,这是malloc的一种已经确立的模式,不这样做通常会导致错误的代码。相比之下,直接写sizeof new T可能并不明智,但在宏扩展的上下文中可能会出现。 - Konrad Rudolph
2
这是一种不错但有点奇怪的写法,用于表达sizeof(int *)。我要补充说明的是,这种写法可能会令人困惑,因为它很可能被理解为sizeof( int ) - Andrew Henle

19

new运算符返回分配内存的指针。new int将返回一个指针,因此sizeof new int;将返回一个指针的大小。这是有效的代码,这里没有未定义行为

警告是合法的,只是警告关于副作用对操作数的影响,这是因为sizeof的操作数不会被计算。

例如:

int i = 1;
std::cout << i << '\n';     // Prints 1
size_t size = sizeof(i++);  // i++ will not be evaluated
std::cout << i << '\n';     // Prints 1

4
有趣的是,很容易让i++被评估:cpp.sh/9774o - Dan M.
6
@DanM.; int[i++] 将在运行时被评估,变长数组除外。请注意,C++ 不允许 VLA,但 GCC 和 clang 提供了这个扩展功能。 - haccks
是的,我知道。只是一个奇怪的陷阱。int(*)[i++]也是一样,取决于实现是否进行评估。 - Dan M.
7
这是未指定的行为。如果大小表达式是 sizeof 运算符操作数的一部分,并且更改大小表达式的值不会影响运算符的结果,则无法确定是否评估大小表达式。参考链接中有详细信息:https://port70.net/~nsz/c/c11/n1570.html#6.7.6.2p5 - Dan M.
1
@haccks 这个规则涉及到VLA。在C++标准中没有VLA。 - Dan M.
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接