6

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.

2
  • 9
    and I want to create a variable-sized array -- In C++, this is spelled std::vector. Commented May 1 at 6:01
  • 3
    In current C++, just assume that if you have to type new (outside of datastructure internals) you're not using C++ as it is intended to be used. Even though many "teachers" still teach you to use "new". Commented May 1 at 6:27

2 Answers 2

14

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.

Sign up to request clarification or add additional context in comments.

Comments

4

The other answer already answers the immediate question, involving raw C arrays.

However - in C++ it is recommended to use std::vector for dynamic sized arrays.

std::vector offers many advantages over raw C arrays, including automatic memory management.
It also solved the syntax awkwardness that probably confused you:

  1. An "array" of pointers to Person (initialized with size elements) would be:
    std::vector<Person*> arr(size);
    
  2. A pointer to an "array" of Persons would be:
    std::vector<Person> * pArr; 
    

A side note:
In C++ it is recommended to avoid using raw new/delete in general.
Most situations where you would need it could be solved by using standard containers (like std::vector) or smart pointers.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.