c++syntaxnew-operatordynamic-arrays

Associativity of '*' operator in a 'new' statement in C++


I have a user-defined class Person and I want to create a variable-sized array (size taken at runtime) of Person pointers. The following code works as expected.

Person **arr = new Person* [size];

However, I didn't understand exactly whom the * operator is associated with. I tried putting paranthesis like:

  1. new ((Person*)[size])
  2. new (Person (*)[size])

Only the second option works.

This seems counterintuitive as in a regular static declaration, Person* arr[10] would mean an array of Person* type (Array of Person pointers) (associativity with Person).
While Person (*arr)[10] would mean a pointer to an array of Person type (associativity with arr).

Edit: As pointed out by @Jan Schultke I realised that new Person* [size] and new (Person (*)[size]) don't have the same effect. One returns Person** and the other returns Person (**)[size]. Also, the second does not allow size to be a variable.

Again, I know I can use vector for dynamic arrays. I am learning OOP methodology lately, focussing on the concepts of programming language C++, and my aim is to get on grips with what goes on under the hood, rather than simply using a library.


Solution

  • Grammatically, what follows the new keyword is a new-type-id, which is a limited form of abstract-declarator. When you write new Person*, the principles are the same as if you wrote:

    using n = Person*;
    // or
    void f(Person*);
    // or
    auto f() -> Person*;
    

    To read abstract-declarators, imagine that there is a variable name in the declaration, like:

    Person *p;
    

    Therefore, the * makes the type a pointer, and new Person* is allocating a new pointer.

    new Person*[size] allocates a new array size 10 of pointers (not a pointer to an array) because [size] has greater precedence in declarators than *.

    Other cases

    new (Person (*)[size]) is allocating a new pointer to a Person[size] array. What you're doing here is using the alternative new-expression syntax where you provide a type-id in parentheses, and that works like:

    using T = Person(*)[size];
    new T;
    

    new ((Person*)[size]) is simply gibberish. It's as if you wrote a C-style cast in a type, like:

    using T = (Person*)[size];
    

    While Person (*arr)[10] would mean a pointer to an array of Person type (associativity with arr).

    I'm not sure why you're surprised by the behavior. Person(*arr)[10] declares a pointer to an array, and new (Person(*)[10]) allocates a new pointer to an array. The effect of parentheses is identical in both cases.