我编写了一个简单的代码,如下所示:

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函数调用中设置断点并逐步通过调试器运行它时,程序会正确输出所有内容,并像应有的那样在main的末尾终止。如果我不使用调试器,则它要么在输出“{”后崩溃,要么输出整个“{{1,2,3,45}”和一个断言失败“Program:...”表达:_CrtIsValidHeapPointer( pUserData)...“

我很好奇为什么会这样。另外,我在Windows 8上使用Visual Studio。

编辑:我是using namepsace std。请不要评论使用 namespace 或如何更好地编写此代码。我对这个问题的原因完全感兴趣。

最佳答案

编辑响应评论中的其他问题。

为了快速起见,是的,它将“仍然”作为一个指针,是的,当您添加4时,它将使用clang和gcc进行编译。

但是,发生了几件事情,我的最初答案是一个简化。问题在于您的表达式一开始的格式不正确,因此尚不清楚该表达式的计算结果或类型。考虑



资料来源:http://en.cppreference.com/w/cpp/language/new

就像说的那样,方括号中必须有一个表达式。这使得很难说表达式是否仍将计算为指针。格式正确的new表达式实际上将计算为一个指针,无论它具有多少维,即使它具有零。当我在这里说指针时,我严格来说是表示形式,而不是类型。

关键是,类型(至少在“内部” new中)会有所不同,具体取决于您拥有的尺寸数。所以,不管你做什么

new int
new int[6]
new int[12][14]

表示是相同的(一个指针),但是new看到的类型在每种情况下都是不同的。编译器能够响应new中的不同类型(类比地认为是函数重载)。特别是,当类型是数组类型时,可以使用包含多个元素的带有括号的初始化程序列表来初始化新内存。

我最好的猜测是,由于VS接受不带表达式的方括号,因此它正在为单个intint[0]分配内存。在前一种情况下,错误地允许您将其初始化为好像是数组类型,而在后一种情况下,分配的内存仍然不足。然后,您的main会写一个堆保护,该堆保护可以在 Debug模式下捕获此类事件。在main的末尾或程序终止时检查此问题时,您看到了这些症状。输出中的不稳定是由于不同的堆布局或由于输出流中的缓冲引起的。

原始答案

您的new表达式(如果格式正确)将具有标量类型,这意味着结果是“单个值”。该单个值是一个指向整数的指针,特别是指向您要创建的数组开头的指针。这就是用C++表示“动态数组”的方式。类型系统不“知道”其大小。

您正在尝试使用4个值的初始化列表来初始化此单个指针值。这不行。我不确定这是否应该编译。它当然不能使用clang或gcc进行编译,而令我惊讶的是它在Visual Studio中可以工作。

08-05 05:16
查看更多