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[]
    删除第二个吗
  • 还有什么我应该注意的区别吗
  • 当软件的其他部分需要第二种情况时,我可以安全地删除括号并将第二种情况转换为第一种情况吗
  • 代码由第三方软件生成(并由软件的其他部分使用),因此我不能只是“使用vector”

    这是一个简单的例子:

    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(*)转换
    to
    int*
    @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:the
    new 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;
    }