#include <stdlib.h>
void *operator new[](size_t size, int n){
if( size != 0 && n != 0 )
return calloc(n, size);
return calloc(1, 1);
}
int main(){
int * p1;
const int i = 0;
// p1 = new (20) int[i] ; // Case 1 (OK)
p1 = new (20) (int[i]); // Case 2 (Warning)
if( p1 == 0 )
return 1;
return 0;
}
This code (https://godbolt.org/g/hjo7Xn) compiles successfully with Clang 6.0.0, however, GCC 7.3 issues a warning saying that zero-length arrays are forbidden in C++. If the parentheses are removed (Case 1), the warning goes away.
Unlike statically allocated zero-length arrays (C++03:8.3.4/1), dynamically allocated zero-length arrays are allowed (C++03:5.3.4/6). Nevertheless, in the C++ Standard the latter are explicitly allowed only when following one of the two possible syntax paths of the new-expression, that is, the one with new-type-id and without parentheses (Case 1).
Is it allowed by the C++ Standard to use the new-expression with a zero-length array following the second syntax path, that is, with type-id and parentheses (Case 2)?
The only related quote is C++03:5.3.4/5:
When the allocated object is an array (that is, the direct-new-declarator syntax is used or the new-type-id or type-id denotes an array type), the new-expression yields a pointer to the initial element (if any) of the array.
The wording (if any)
would allow an array with no elements, however, it does not seem clear if it refers to both cases or only to the one with new-type-id and without parentheses (Case 1).
Thanks in advance.
Notes:
If the constant-expression (5.19) is present, it shall be an integral constant expression and its value shall be greater than zero.
The expression in a direct-new-declarator shall have integral or enumeration type (3.9.1) with a non-negative value.
When the value of the expression in a direct-new-declarator is zero, the allocation function is called to allocate an array with no elements.
new-expression:
::
opt
new new-placementopt
new-type-id new-initializeropt
::
opt
new new-placementopt
( type-id ) new-initializeropt
Dynamic arrays are resizable and provide random access for their elements. They can be initialized with variable size, and their size can be modified later in the program. Dynamic arrays are allocated on the heap, whereas VLAs are allocated on the stack.
Zero-length array declarations are not allowed, even though some compilers offer them as extensions (typically as a pre-C99 implementation of flexible array members).
One limitation of arrays is that they're fixed size, meaning you need to specify the number of elements your array will hold ahead of time. A dynamic array expands as you add more elements. So you don't need to determine the size ahead of time.
You can't. The size of an array allocated with new[] is not stored in any way in which it can be accessed. Note that the return type of new [] is not an array - it is a pointer (pointing to the array's first element). So if you need to know a dynamic array's length, you have to store it separately.
With parenthesis you have a regular type-id, instead of the special syntax called a new-type-id that supports dynamic array size.
As of C++17 the standard makes no special provision for this use of a type-id, so the question boils down to whether you can write
auto main() -> int
{
using Argh = int[0];
}
You can't, because a type-id's type is defined in terms of a fictitious “declaration for a variable or function of that type that omits the name of the entity” (C++17 §11.1/1), and for declaration of an array variable the rule is “If the constant-expression (8.20) is present, it shall be a converted constant expression of type std::size_t
and its value shall be greater than zero” (C++17 §11.3.4/1).
Now there's a fair bit of interpretation in this. E.g. without such reasonable interpretation the last quote would not reasonably say that the array size must be non-negative and representable as a size_t
. Instead, with no reasonable interpretation, it would literally say that a declaration such as
int x[42];
is invalid (of course it isn't), and would have to be expressed as
int x[std::size_t(42)];
Determining what is a reasonable interpretation or not used to be easy. One could just ask, does it make sense? So for the case above the answer would be no, and one could ditch that possibility.
However, to some degree with C++14 and increasingly more so with C++17 I find that that earlier dependable technique fails. Since the question at hand is about C++03 functionality, however, I think you can trust this answer. But if it were a question about C++14 or later stuff, then do keep in mind that any apparently clear-cut answer probably involves some subjective interpretation that probably can't be resolved by asking whether it makes sense or not.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With