3

根据 C++03 标准 (5.3.4/7):

当 direct-new-declarator 中表达式的值为零时,调用分配函数来分配一个没有元素的数组。

根据我的阅读,这意味着该代码是合法的并且具有特定的效果:

#include <iostream>
#include <string>
using namespace std;

class A
{
public:
    A() : a_(++aa_) {};
    int a_;
    static int aa_;
};
int A::aa_ = 0;

int main()
{
    A* a = new A[0];
    // cout << "A" << a->a_ << endl; // <-- this would be undefined behavior
}

当我在调试器下运行这段代码时,我看到A' 的构造函数从未被调用过。 new不抛出,并返回一个非空的、明显有效的指针。但是, at 的值a->a_是未初始化的内存。

问题:

  1. 在上面的代码中,a实际指向什么?
  2. “分配一个没有元素的数组”是什么意思?
  3. 分配一个元素为零的数组有什么实际用途?
4

3 回答 3

5

在上面的代码中,a 实际指向什么?

指向一个零元素数组。

“分配一个没有元素的数组”是什么意思?

这意味着我们得到了一个有效的数组,但大小为零。我们无法访问其中的值,因为没有,但是我们现在每个零大小的数组都指向不同的位置,我们甚至可以创建一个指向过去的迭代器&a[0]。所以我们可以像使用其他数组一样使用它。

分配一个元素为零的数组有什么实际用途?

它只是使您免于n = 0每次调用时检查new。请注意,大小为零的静态数组是非法的,因为静态数组具有来自常量表达式的静态大小。此外,允许您使用一对迭代器调用任何标准或自定义算法。

于 2012-06-17T19:53:18.100 回答
4

您的a点(有效)为零连续元素,并且已经构造了零元素。表达式a->a_与 相同a[0].a_,超出范围,因此行为未定义。

此外,“处的值a->a_是未初始化的内存”这句话似乎没有意义:一个值就是一个值,而内存就是内存——一个值不能内存。由于我们已经确定您永远不能取消引用a,因此要求任何类型的变量值a指向:a只是没有指向任何有用的地方是没有意义的。

delete[] a;释放分配的内存并销毁所有零对象仍然是完全有效的(并且是预期的?!) 。

(请注意,C 的malloc函数也可以使用 argument 调用0,但不能保证它的返回值除您可以之外free。在 C++ 中,::operator new[]实际上每次都需要返回一个不同非 null值(取决于重用值已传递给::operator delete[])。

于 2012-06-17T19:51:46.343 回答
3

它归结为:new whatever[0]导致返回一个有效地址,与任何其他当前分配的对象不同,但您不能取消引用。

它的典型用途是分配不同大小的数组的代码,因此有时您可能有一个包含正数元素的数组,但有时是一个包含零元素的数组。即使您不能取消引用它,使用“正常”(有效)指针而不是(例如)空指针仍然可以简化相当多的代码。

仅举一个例子,考虑存储数组开始地址的典型情况,以及数组末尾之外的地址(并且具有从一个到另一个遍历的循环)。使用空指针,您不能进行这样的算术运算,因此任何处理过尾指针的事情都需要对空指针进行特殊的大小写。在您无法取消引用的有效非空指针的情况下,您仍然可以在没有任何特殊情况的情况下形成起始地址和结束地址。您编写的普通循环在数组为空时执行零次迭代,而不是只为非空指针执行循环的特殊情况代码。

于 2012-06-18T01:18:29.780 回答