4

In C, I do

int (*ptr)[100];
ptr=malloc(sizeof *ptr); // this is the easy/error proof way of doing it

Is there an error proof C++ way of doing the same with new operator

int (*ptr)[100];
ptr=new __what_comes_here?
sjsam
  • 21,411
  • 5
  • 55
  • 102
  • 7
    In C++ you'd probably do `std::vector v(100);`. – Matteo Italia Aug 01 '16 at 05:26
  • 5
    The elegant error-proof way of C++ is to avoid arrays, pointers, or `new`. – n. m. could be an AI Aug 01 '16 at 05:33
  • How do you use `p`? `(*p)[n]` or `p[0][n]`? – n. m. could be an AI Aug 01 '16 at 05:41
  • 1
    @n.m. : What difference that would make? – sjsam Aug 01 '16 at 05:44
  • I just wonder what you consider elegant. In my view the double indirection is superfluous and therefore should be avoided in favor of `int* p; ...; p[n]`. – n. m. could be an AI Aug 01 '16 at 05:52
  • @n.m. I understand what you meant and I agree with your view. But the question is not whether to avoid it or not in favor of something else? had you have deal with it some time, how you would've represented it is the question. – sjsam Aug 01 '16 at 05:57
  • If the question is "what is an elegant way to drive screws with a hammer", then the only sensible answer is "don't". – n. m. could be an AI Aug 01 '16 at 05:59
  • @n.m., to me it appears that there is No choice left. `ptr = new __what_comes_here` as asked in the question, is simply **not possible**. It results in compilation errors; e.g. [ideone](http://ideone.com/dn6Tjl)(from a deleted answer). The only choices are `int* p`, `std::vector`, `std::array`, `std::unique_ptr` if the dynamic array is required to be allocated. – iammilind Aug 01 '16 at 06:06
  • 1
    On a lighter note, if you do want to use `new` and accomplish the same effect as in C, use `operator new()` :) – Abhineet Aug 01 '16 at 06:36

4 Answers4

3
int (*ptr)[100];

means ptr is a pointer, which should hold an address of an array of 100 integers. In other words, technically if you have, something like:

int arr[100];  // automatic (compile time allocated) object of 100 integers

Then you may want to use:

ptr = &arr;

But that is not the case here. So you can do with a simple pointer. If you want to go dynamic then you either go for malloc equivalent:

int *p = new int[100];  // do `delete[] p` later to reclaim memory

Note that, p is a simple pointer, which holds the address of the first integer of the dynamically allocated array.

But better practice is to use standard container to avoid any memory management:

std::vector<int> v(100);

If the size 100 is fixed then you may use:

int a[100];  // C-style

Or

std::array<int, 100> arr;  // C++11 onwards

If you require new and don't have luxury of using above facilities but still want automatic reclamation of memory then use unique_ptr as following:

std::unique_ptr<int[]> p(new int[100]);
Community
  • 1
  • 1
iammilind
  • 68,093
  • 33
  • 169
  • 336
  • He's looking for how to *not* have to put the enumeration in the `new` statement, but deduce it from the pointer declaration the same as he is able to do with malloc. – kfsone Aug 01 '16 at 05:32
  • 2
    @kfsone, you are downvoting without any liability. A pointer to array is NOT required to hold a memory allocated by `new/malloc`. OP is probably not well aware of the syntax in C++. `int (*p)[N]` is not required to hold a dynamically allocated memory. – iammilind Aug 01 '16 at 05:38
1

The way I'm showing here is obviously not a great solution, I just wanted to sort of answer the question in a unique way.

template<typename>
struct deref;

template<typename T>
struct deref<T*>
{
    typedef T type;
};

int main() {
    int (*ptr)[100];
    ptr = new deref<decltype(ptr)>::type[1];
    return 0;
}

I know that the [1] is obviously highly suspicious but without it, the result of the new seems to just decay to a int*. So I think that adding it causes only the "outer" array to decay and leave the inner intact.

Also this means that you need to call delete[] to clean it up and not cause undefined behaviour.

If you want to convince yourself that this actually allocates the necessary space and it can access it correctly you can see the output of godbolt in an example.

PeterT
  • 7,981
  • 1
  • 26
  • 34
  • The `[1]` means you're allocating a single-element array of `int[100]`s, rather than a 100-element array of `int`s. So you get a pointer to the first `int[100]` element in that new array. It _shouldn't_ matter in any practical way, as both will give you a block of 400 bytes (for a 32-bit `int`) and `delete[]` would need to be able to handle either one being pointed to by its parameter without regard to the type, I expect. – TBBle Aug 03 '16 at 12:35
0
typedef int IntArray[100];

int main()
{
    IntArray* p = new IntArray[1];

    delete[] p;
    return 0;
}

Note that you must deallocate thus allocated array with delete[].

Leon
  • 31,443
  • 4
  • 72
  • 97
0

Not quite what you asked for, but you can what you want using template type deduction.

template <typename T, std::size_t N>
void populate_ptr(T (*&ptr)[N])
{
    // Its a shame the return value of new T[N] is T*, not T(*)[N]
    ptr = reinterpret_cast<T(*)[N]>(new T[N]);
}

int (*ptr)[100];
populate_ptr(ptr);
// Don't forget to delete[](ptr) later!

You can't deduce templates on return values, so you can't use assignment, but passing-by-reference should be equivalent for all use-cases.

Not that this is a great way of handling this, but being able to do template type deduction against C-style arrays comes in handy from time to time..

TBBle
  • 1,436
  • 10
  • 27
  • While `operator new[]` returns `void*` the returned type of a new expression is actually `T*` – PeterT Aug 01 '16 at 13:02
  • You can also replace the reinterpret cast with `typedef T arrType[N]; ptr = new arrType[1];` which is the same "trick" I and Leon used. – PeterT Aug 01 '16 at 13:06
  • Thanks @PeterT, I fixed the comment about `operator new[]`'s return type. I'm not sure about the `typedef` trick, because (it's nick-picky) that array allocates a one-element array of 100 element `int` arrays, rather than a 100-element array of `int`s. I can't easily imagine a practical use-case for that to be different -- some kind of `operator new[]` overload that redirects large-by-count arrays into a different pool, perhaps? Anyway, my intention was to illustrate a safe way of using `new T[N];` where T and N were extracted from the pointer's type. – TBBle Aug 03 '16 at 12:30