C++ 为什么初始化器列表初始化需要堆分配数组的大小?

C++ 为什么初始化器列表初始化需要堆分配数组的大小?,c++,c++11,initialization,initializer-list,C++,C++11,Initialization,Initializer List,虽然我会写 int n[] {1, 2, 3}; 我不会写字 int *m = new int[] {1, 2, 3}; 应该是哪一个 int *m = new int[3] {1, 2, 3}; >原因是什么?请记住 < < /> >实际上是C++中的运算符。 这是因为新操作符是如何定义的;i、 它需要请求的内存大小作为显式输入参数。因此,它不会由初始值设定项列表成员的计数来推断。要理解这一点,您需要了解new运算符是如何工作的。new返回指向新分配内存块开头的指针。所以当我们说 in

虽然我会写

int n[] {1, 2, 3};
我不会写字

int *m = new int[] {1, 2, 3};
应该是哪一个

int *m = new int[3] {1, 2, 3};

>原因是什么?

请记住<强> < < /> >实际上是C++中的运算符。


这是因为新操作符是如何定义的;i、 它需要请求的内存大小作为显式输入参数。因此,它不会由初始值设定项列表成员的计数来推断。

要理解这一点,您需要了解new运算符是如何工作的。new返回指向新分配内存块开头的指针。所以当我们说

int* p = new int;
int* foo = new [3];
我们正在分配内存以包含单个元素。但是当我们说

int* p = new int;
int* foo = new [3];
我们正在为int类型的元素分配一个内存块,其中“3”是整数类型的内存块数。这告诉编译器为3个整数分配内存。 当我们这样做的时候

int* p = new int[3]{1,2,3}
 int* p = new int[] {1,2,3}
我们要求编译器分配3个存储integer类型值的内存位置。同时,我们也为这些内存位置赋值

现在如果我们这样做

int* p = new int[3]{1,2,3}
 int* p = new int[] {1,2,3}
我们没有告诉编译器要分配多少内存,但同时我们试图分配给3个内存位置,但我们没有分配那么多内存。在这种情况下,编译器只分配1块内存。所以第一个值被赋值。这将导致运行时错误

现在奇怪的是,如果允许下面的代码,并且编译器足够聪明,可以分配3个值

int n[] = {1, 2, 3}
在这种情况下为什么不呢

int *p = new int [] {1,2,3}
我认为这是一个问题,因为新运营商是如何设计的。您可能可以尝试重载新的运算符并绕过此问题

希望这有帮助

编辑:我在VS中尝试了一些伪代码。如果你这样做的话

int* p = new int [] {1,2,3}
int* p = new int []{1}
这是一次撞车。但当你这么做的时候

int* p = new int [] {1,2,3}
int* p = new int []{1}

这很好。这证明编译器将其解释为只分配1块内存的命令。

您的意思是
intn[]={1,2,3}?您总是可以这样做的,所以谁想使用
new
分配数组呢。也许上面的代码不被允许似乎没有很好的理由。请看@dyp将其转化为一个答案,这是一个很好的问题,这是正确的答案。这是一个悬而未决的问题。@ShafikYaghmour我无法在EWG中找到这个问题的当前状态。“我们没有告诉编译器要分配多少内存”编译器可以看到有三个初始值设定项,就像您提到的
intn[]={1,2,3}
案例一样。“在这种情况下,编译器只分配1块内存”不,这是非法的(通过语言语法禁止)。如果MSVC接受它,它要么是一个扩展,要么是一个bug。我们确实支持一些有趣的东西,比如
newauto(5)
。虽然
new
是一个操作符,但它仍然不是一个可以通过重载替换整个语义的操作符。事实上,您只能重载/替换由“内置运算符
new
”(新表达式)调用的分配和解除分配函数。我没有告诉任何关于重载的事情。我的意思是,当你因为“新”而制造新汽车时,5应该在那里。就是这样。对不起,我可能误解了你的答案。你是说它不工作是因为它没有被指定在当前工作(OP的代码在当前的C++中是非法的)?或者它不起作用是因为有一些根本原因,它不能(甚至理论上)起作用?