我写了一个简单的代码如下:
void show(const int a[], unsigned elements);
int main()
{
show(new int[]{1, 2, 3, 45}, 4); //does not work
}
void show(const int a[], unsigned elements)
{
cout << "{ ";
for (int i = 0; i < elements; i++)
{
cout << a[i];
if (i != elements - 1)
cout << ",";
cout << " ";
}
cout << "}";
}
它应该只输出{1,2,3,45}。如果我在括号中包含大小
show(new int[4]{1, 2, 3, 45}, 4);
然后它的工作原理。所以我自然会假设如果我以这种方式编写new
,我必须指定大小(虽然我认为给它一个初始化列表会暗示大小)。但是,奇怪的是,当在show函数调用中设置断点并且我一步一步地通过调试器运行它时,程序正确地输出所有内容并在它应该的主端结束。如果我不使用调试器,它会在输出'{'之后崩溃,或者输出整个事物“{1,2,3,45}”并且断言失败“Program:...”表达式:_CrtIsValidHeapPointer( pUserData)...“
我很想知道它为什么会这样。另外,我在Windows 8上使用Visual Studio。
编辑:我是using namepsace std
。请不要评论使用命名空间或如何更好地编写此代码。我对这个问题的原因完全感兴趣。
答案 0 :(得分:1)
编辑在评论中回复其他问题。
要快速,是的,它“仍然”是一个指针,是的,当你添加4时,它会用clang和gcc编译。
然而,有几件事情正在发生,我最初的答案是简化。问题是你的表达式一开始并不是很好,所以不清楚它应该评估什么或类型应该是什么。考虑
如果type是数组类型,则必须将除第一个之外的所有维度指定为正整数常量表达式(直到C ++ 14)转换为std :: size_t类型的常量表达式(自C ++ 14起),但是第一维可以是任何可转换为std :: size_t的表达式。
来源:http://en.cppreference.com/w/cpp/language/new
正如它所说,无论哪种方式,括号中都必须有一个表达式。这使得很难说表达式是否仍然评估为指针。格式良好的new
表达式确实会对指针进行求值,无论它有多少维度,即使它没有。当我在这里说指针时,我严格意味着表示,而不是类型。
重点是类型,至少“内部”new
,根据您拥有的尺寸而有所不同。那么,你是否
new int
new int[6]
new int[12][14]
表示是相同的(指针),但new
看到的类型在每种情况下都是不同的。编译器能够响应new
中的不同类型(通过类比函数重载来思考)。特别是,当类型是数组类型时,可以使用包含多个元素的支撑初始化列表初始化新内存。
我最好的猜测是,因为VS接受没有表达式的括号,所以它为单个int
或int[0]
分配内存。在前一种情况下,它错误地允许你支持初始化它就好像它是一个数组类型,而在后一种情况下,分配的内存无论如何都不够。然后你的main
写了一个堆保护器,它可以在调试模式下捕获这种东西。在main
结束时或程序终止时检查时,您会看到症状。输出中的碎片是由于不同的堆布局或由于输出流中的缓冲造成的。
原始回答
你的new
表达式,如果格式正确,则会有标量类型,这意味着结果是“单值”。该单个值是指向整数的指针,特别是指您尝试创建的数组开头的整数。这就是“动态数组”在C ++中的表示方式。类型系统不“知道”它们的大小。
您正尝试使用4个值的初始化列表初始化此单个指针值。这应该不起作用。我不确定这应该编译。它肯定没有用clang或gcc编译,我很惊讶它在Visual Studio中有效。