C++ 新字符[n]和新字符[n]之间的差异
C++ 新字符[n]和新字符[n]之间的差异,c++,memory-management,C++,Memory Management,newchar[n]和new(char[n])之间有什么区别吗 在生成的代码中有第二种情况,g++(4.8.0)给了我 这让我想到这两者是否相同 newchar[n]表示“分配n类型char的对象” new(char[n])是否表示“分配一个类型为数组的n个char的对象” 删除第一个是清楚的 我应该用delete或delete[]删除第二个吗 还有什么我应该注意的区别吗 当软件的其他部分需要第二种情况时,我可以安全地删除括号并将第二种情况转换为第一种情况吗 代码由第三方软件生成(并由软件的其他
newchar[n]
和new(char[n])
之间有什么区别吗
在生成的代码中有第二种情况,g++(4.8.0)给了我
这让我想到这两者是否相同
newchar[n]
表示“分配n
类型char
的对象”new(char[n])
是否表示“分配一个类型为数组的n个char的对象”
delete
或delete[]
删除第二个吗int main (void)
{
int n(10);
int *arr = new (int[n]); // removing parentheses fixes warning
*arr = 0; // no "unused variable" warning
return 0;
}
事实上,两者是平等的
以下是汇编程序生成的代码(只是一个不可忽略的差异):
int n=10;
int*i=new(int[n]);
int*j=新的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:添加$0x1,%eax
main()+32:shl$0x2,%eax
main()+35:mov%eax,(%esp)
main()+38:调用0x401620//void*运算符new[](无符号整数);
main()+43:mov%eax,0x18(%esp)
!int*j=新的int[n];
main()+47:mov 0x1c(%esp),%eax
main()+51:shl$0x2,%eax
main()+54:mov%eax,(%esp)
main()+57:调用0x401620//void*运算符new[](无符号整数);
main()+62:mov%eax,0x14(%esp)
!
!i[1]=123;
main()+66:mov 0x18(%esp),%eax
main()+70:添加$0x4,%eax
main()+73:movl$0x7b,(%eax)
!j[1]=123;
main()+79:mov 0x14(%esp),%eax
main()+83:添加$0x4,%eax
main()+86:movl$0x7b,(%eax)
您必须通过delete[…]删除
newt[N]
生成一个类型为T
的N
元素数组
new(T[N])
生成类型为T[N]
的单个对象
效果相同(两个表达式都产生一个T*
,它指向数组的第一个元素,需要使用delete[]
(参见5.3.4/5)删除,但显然T[N]在后一种情况下必须是一个有效的类型,所以<代码> n< /Cord>必须是常量表达式,而在前一种情况下,数组是新表达式的动态参数。 这里的基本问题是C++不允许数组绑定<代码> [n]。
在类型中使用,除非n
是一个常量表达式。g++和其他一些编译器有时会允许它,但当您开始混合可变长度数组和模板时,不可能获得一致的行为
明显的例外是int*p=new int[n];
有效,因为这里的[n]
在语法上是new
表达式的一部分,而不是提供给new
的类型的一部分,并且new
知道如何创建在运行时确定长度的数组
// 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;
}
但是,从语义上讲,在使用任何最后的[C]
将类型转换为数组类型之后,新表达式只关心它是否处理数组。关于表达式类型的所有要求,是否使用new[]
和delete[]
,等等,都是这样的当分配的类型是数组时,而不是“使用数组新语法时”。因此在上面的示例中,p1
、p2
和p3
的初始化都是等效的,并且在所有情况下,delete[]
都是正确的释放形式
<>代码> P4<代码>是有效的,但是代码< > p5< /> >和<代码> p6<代码>是不正确的C++。无论如何,当不使用<代码> -PoANDICT<代码>时,G++会允许它们,类推,我期望代码的初始化< P4<代码>,<代码> P5<代码>,和<代码> p6<代码>也都是等价的。@ MM的拆卸支持这就是结论
是的,从这类表达式中删除“额外”括号应该是一个安全的改进。正确的删除是delete[]
类型。编译器和版本是什么?gcc 4.8.0,添加到问题中我很惊讶它允许从int(*)转换
toint*
@aschepler我认为VLA的类型是int*
。它们int(*)[n]
不能作为类型存在。哦,我明白了。“当分配的对象是数组时(即使用noptr新声明符语法或新的类型id或类型id表示数组类型),新表达式将生成指向初始元素的指针“[]
比new
具有更高的优先级,因此new t[N]
不应该被解释为与new(t[N])
相同吗?“this one make N elements”,“this one make a single array”的区别不存在,或者至少我看不到它。@name:thenew t[N]
形式是一种不同的语法结构,N
是数组新表达式的一部分,而不是该类型。@Ludanton:区别在于new T[rand()]
有效,但new(T[rand()])
无效。T[N]
是一种类型,当N
是一个常量表达式时。对,这在你的段落中,我并不反对。这是要点。如果两个语法都有效,它们的意思和作用是相同的。根本没有区别。我要指出\u Znaj
是void*操作符new[](unsigned int)的g++-manglish;
-1:仅仅因为两件事为一个简单的代码框架生成相同(或相似)的汇编代码并不意味着代码“相等”甚至相等;汇编是非常低级的,不关心类型,而
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)
// 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;
}