rb612
rb612

Reputation: 5563

Preventing array decay when allocating memory on the heap?

If I write int* a = new int[5]; and then I call sizeof(a) or sizeof(*a), I don't get the information I want because the array has decayed into a pointer. However, I'm wondering if there's a way we can do something like this:

int[5]* a = new int[5];

I'm pretty sure we're able to do this with stack memory but I'm not sure if there's any way to do it for heap memory, since the above will not compile. And if there isn't a way, is there a reason for not having this as a possibility?

Upvotes: 3

Views: 165

Answers (3)

paxdiablo
paxdiablo

Reputation: 881383

There's no getting around the fact that C++ was originally just a front end for C and, as such, carries a fair amount of baggage from the original language. Such as many things in the <cXXX> headers, and the behaviour of many operations, like array decay(a).

If you want a more convenient array type, C++ has such a beast in std::vector. If you pass that around, you will not be subject to the decay you may see when using the more low-level memory allocation methods. See, for example:

#include <iostream>
#include <vector>

void someFunction (const std::vector<int> &myVec) {
    std::cout << myVec.size() << std::endl;
}

int main() {
    std::vector<int> myVec({ 3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 9, 0 });
    std::cout << myVec.size() << ' ';
    someFunction(myVec);
}

which outputs 13 13, showing that the size is the same outside and inside the function (it's also the size in elements rather than bytes as given bt sizeof, the former usually being a far more useful measure).


When mentoring or training C++ programmers, I always warn them about being a "C+" programmer, one who was raised on C and never really made the full transition to C++ (things like continuing to use raw arrays instead of vectors, rolling you own data structures when perfectly adequate ones are in the standard library, using malloc/free or printf, and so on).

You would be wise thinking of C and C++ as related but totally different languages, and adopting the C++ way of thinking as much as possible.


(a) Interestingly, your specific question does not have an array decaying into a pointer. The new call actually returns a pointer directly so there's no decay involved.

Where you would see decay is in something like:

void someFunction (int x[]) {
    // Pointer to first element here, size is int-pointer-size.

    std::cout << sizeof(x) << std::endl;
}

:

// Array here, size is 13 * int-size.

int xyzzy[] = { 3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 9, 0 };
std::cout << sizeof(xyzzy) << std::endl;

someFunction(xyzzy);

Upvotes: 5

xskxzr
xskxzr

Reputation: 13040

Of course you can, via a two-dimension array, e.g.

int (*a)[5] = new int[1][5];

Note: this code is just for language-lawyer purpose and is not recommended in practice. If this is an XY problem, you should use std::vector or std::array instead as other answers suggested.

One of the reasons why new int[N] returns a pointer to its first element instead of a pointer to itself like non-array new, is to make the use of the array easier. For example, with auto a = new int[5], you can access the array by simple a[n] instead of (*a)[n].

Upvotes: -1

Fantastic Mr Fox
Fantastic Mr Fox

Reputation: 33864

There is no way to store this information in the pointer. And there is no separate construct that will let you do this the way you want. Your options are:

  1. Store the size of the array separate to the array: const int a_size = 5; int *a = new int[a_size].
  2. Use a C++ construct to handle this for you: std::vector<int> a(5); a.size()

I would highly recommend option 2. Not simply because its easier and std::vector gives more functionality. But because the RAII style construct manages the memory for you meaning you don't need to remember to call delete[] on the memory later. You also can't accidentally call delete on the memory later since you might have forgotten that it is an array.

Upvotes: 3

Related Questions