sizeof depends on type information (only available at compile time) to do its thing. The type information required by sizeof to obtain the proper size of an array is unavailable everywhere except in the function that declared the array. This is because it's technically impossible to pass an array to a function. int Getsize(int Array[]) is merely syntactic sugar for int Getsize(int *Array). While in main() the identifier X refers directly to an array on the stack, in Getsize() the identifier Array refers to a pointer to an array. Pointers are simply integers. They don't have any information about what they point to, other than where it is.
In general, it's impossible to obtain the size of an array. Under specific cases, its possible to obtain the size of arrays on the stack using template magic:
It's not impossible helios, you just did it. ;) Also, an array doesn't have to be on the stack to use template magic.
The problem is that C++ came from C, and C did what helios said for the 1st dimension of an array, it would just chuck the size and degrade decays it down to a pointer when passing it around, presumably because passing an array by value is an expensive operation and nobody would want to do it. However, the type would retain all of the other dimensions if any existed.
C++ sorta kinda did a thing where it actually kept the complete type including the size of the 1st dimension, but it would only be accessible if the array was passed as a reference. This was for backward compatibility with C. Since C doesn't have references, this wouldn't break C code compiled under a C++ compiler. Since then, C and C++ have diverged sufficiently that this actually doesn't matter anymore, (C is no longer just a subset of C++) but legacy remains.
It is unfortunate in this case that C++ has C legacy, making things confusing for newbies (and even veterans). FYI, the magic comes from function templates type deduction if you want to look it up. Also, it's usually a better idea that you use a STL container instead of arrays directly as it manages allocation, knows its own size and is just generally safer (you can also pass an STL container by value if you so wish).
It is impossible to find size of dynamically allocated array.
1 2 3 4 5 6 7 8 9
//size_t getSize(...
int main()
{
size_t x;
std::cin >> x;
int* arr = newint[x];
x = 0;
x = getSize(arr);
}
Templates needs to know their parameters in compile time, so you cannot use them here.
Pass by refence will work only if you specify complete type (void f(int (&x)[5]) instead of void f(int (&x)[])), where you already know size of array.
I do not understand, why C++ does not have a method to access size of array. I mean, delete[] does know how many memory it should deallocate, subscript operator knows size and aligment of one element. Why cannot we have access to that as well?
I do not understand, why C++ does not have a method to access size of array. I mean, delete[] does know how many memory it should deallocate, subscript operator knows size and aligment of one element. Why cannot we have access to that as well?
Not all arrays are created with new. If the array is created on the stack or the array is part of another object the size of the array doesn't have to be stored anywhere in memory.
Yes, you have point here, but program still needs to know it's size to poperly deallocate it in destructor/at the end of scope or access another variables stored besides it (for example difference between offsets from object pointer for member array and next member.)
to poperly deallocate it in destructor/at the end of scope
Destructors don't know the size of the memory you pass to them. A::~A() will assume that the actual size of the memory this points to equals sizeof(A). In other words,
1 2
A *p=/*...*/;
delete (char *)p;
is incorrect.
access another variables stored besides it (for example difference between offsets from object pointer for member array and next member.)
I do not understand, why C++ does not have a method to access size of array.
In a sense it does - by supplying container classes in the standard libraries, which manage their own storage and include public methods to query the size.
Again, this function does NOT work in the general case.
cire wrote:
Let's see the template magic that works in the general case.
I think that I may have interpreted this differently on the first read. So long as the important type information is not lost and the code is valid, it works. In order not to loose the important array type info on a dynamically allocated array, you need to do as I stated, as in:
1 2 3 4 5 6
int main()
{
auto& X = *newint[1][5]{{45, 12, 54, 83, 41, 36}};
get_array_size(X);
delete[](X);
}
The line marked isn't valid:
1 2 3 4 5 6 7 8 9 10
#include <cstdlib>
#include <ctime>
int main()
{
std::srand(std::time(0)) ;
unsigned size = std::rand() ;
newint[size] ; // this line is valid
newint[1][size] ; // even this line is invalid
}
That is because type information needs to be known at compile time. Variable `size` is not a compile time constant, making that line invalid. So for dynamic arrays, you're right, it doesn't work for the general case. It only works in the special case where the type info can be known (and not lost) at compile time.
Still if you want runtime allocation size, it is better to use a vector as it deals with the implementation details for a variable runtime dynamically allocated array and you can get the size of it easily.
Perhaps you can quote the line in the standard that requires one to use a compile time constant when using new (and then, perhaps, you can point out one compiler that is compliant with respect to that line.)
Oops, looks like I misread the compiler output. I was wondering why that wasn't working. :/ Yes, the first one is valid. Only the 2nd one isn't. I've modified my answer to reflect this.