23

new char[n]和有什么区别new (char[n])吗?

我在生成的代码中有第二种情况,g++(4.8.0)给了我

ISO C++ does not support variable-length array types [-Wvla]

这让我想这两个是否相同。

  1. new char[n]意思是“分配n类型的对象char
  2. 是否new (char[n])意味着“分配 1 个类型的对象array of n chars”?
  3. 删除第一个很清楚。
  4. delete我应该用or删除第二个delete[]吗?
  5. 还有其他我应该注意的区别吗?
  6. 当软件的其他部分期望第二种情况时,我可以安全地删除括号并将第二种情况转换为第一种情况吗?

该代码是由第三方软件生成的(并由软件的其他部分使用),所以我不能只是“使用矢量代替”。

这是最小的例子:

int main (void)
{
    int n(10);
    int *arr = new (int[n]); // removing parentheses fixes warning
    *arr = 0; // no "unused variable" warning
    return 0;
}
4

3 回答 3

10

这里的基本问题是 C++ 不允许[n]在类型中使用绑定的数组,除非n它是一个常量表达式。g++ 和其他一些编译器有时会允许它,但是当您开始混合可变长度数组和模板时,不可能获得一致的行为。

明显的例外int* p = new int[n];有效,因为这里是表达式[n]的语法一部分,而不是提供给 的类型的一部分,并且确实“知道如何”创建长度在运行时确定的数组。newnewnew

// can be "constexpr" in C++11:
const int C = 12;

int main() {
    int* p1 = new int[C];
    int* p2 = new (int[C]);
    typedef int arrtype[C];
    int* p3 = new arrtype;

    int n = 10;
    int* p4 = new int[n];
    // int* p5 = new (int[n]);  // Illegal!
    // typedef int arrtype2[n]; // Illegal!
    // int* p6 = new arrtype2;

    delete[] p1;
    delete[] p2;
    delete[] p3;
    delete[] p4;
}

但是,从语义上讲,在使用任何 final[C]将类型转换为数组类型之后,new 表达式只关心它是否在处理数组。所有关于表达式类型、是否使用new[]and等的delete[]要求都说“当分配的类型是数组时”,而不是“当使用数组新语法时”。所以在上面的例子中p1p2、 和的初始化p3都是等价的,并且在所有情况下delete[]都是正确的释放形式。

的初始化p4有效,但 C++ 的代码p5p6正确。g++ 在不使用时无论如何都会允许它们-pedantic,并且通过类比,我希望对 , 和 的初始化p4p5都是p6等价的。@MM 的反汇编支持该结论。

所以是的,从这种表达式中删除“额外”括号应该是一个安全的改进。正确的删除是delete[]类型。

于 2013-05-19T13:24:39.257 回答
6
  • new T[N]N创建一个类型为 的元素数组T

  • new (T[N])生成单个类型的对象T[N]

效果是一样的(两个表达式都产生T *指向数组第一个元素的 a 并且需要用delete[](cf. 5.3.4/5) 删除,但显然在后一种情况下T[N]必须是有效类型,所以N必须是一个常量表达式,而在前一种情况下,它是 array-new 表达式的动态参数。

于 2013-05-19T13:04:36.457 回答
3
  new int [n]
  //Allocates memory for `n` x `sizeof(int)` and returns
  //the pointer which points to the beginning of it. 

 +-----+-----+-----+-----+-----+-----+-----+-----+------+------+
 |     |     |     |     |     |     |     |     |      |      |
 |     |     |     |     |     |     |     |     |      |      |
 |     |     |     |     |     |     |     |     |      |      |
 +-----+-----+-----+-----+-----+-----+-----+-----+------+------+


  new (int [n])
  //Allocate a (int[n]), a square which its item is an array
+----------------------------------------------------------------+
|+-----+-----+-----+-----+-----+-----+-----+-----+------+------+ |
||     |     |     |     |     |     |     |     |      |      | |
||     |     |     |     |     |     |     |     |      |      | |
||     |     |     |     |     |     |     |     |      |      | |
|+-----+-----+-----+-----+-----+-----+-----+-----+------+------+ |
+----------------------------------------------------------------+

事实上,两者是平等的。

 

这是汇编程序生成的代码(只是一个可忽略的差异):

int n = 10;
int *i = new (int[n]);
int *j = new int[n];

i[1] = 123;
j[1] = 123;

----------------------------------

!    int *i = new (int[n]);
main()+22: mov    0x1c(%esp),%eax
main()+26: sub    $0x1,%eax
main()+29: add    $0x1,%eax
main()+32: shl    $0x2,%eax
main()+35: mov    %eax,(%esp)
main()+38: call   0x401620 <_Znaj> // void* operator new[](unsigned int);
main()+43: mov    %eax,0x18(%esp)
!    int *j = new int[n];
main()+47: mov    0x1c(%esp),%eax
main()+51: shl    $0x2,%eax
main()+54: mov    %eax,(%esp)
main()+57: call   0x401620 <_Znaj> // void* operator new[](unsigned int);
main()+62: mov    %eax,0x14(%esp)
!    
!    i[1] = 123;
main()+66: mov    0x18(%esp),%eax
main()+70: add    $0x4,%eax
main()+73: movl   $0x7b,(%eax)
!    j[1] = 123;
main()+79: mov    0x14(%esp),%eax
main()+83: add    $0x4,%eax
main()+86: movl   $0x7b,(%eax)

你必须delete通过delete [] ...

于 2013-05-19T12:42:28.337 回答