I used to think that the answer to this question was "100%", but I've recently been pointed to an example that makes it worth thinking twice. Consider a C array declared as an object with automatic storage duration:
int main()
{
int foo[42] = { 0 };
}
Here, the type of foo
is clearly int[42]
. Consider, instead, this case:
int main()
{
int* foo = new int[rand() % 42];
delete[] foo;
}
Here, the type of foo
is int*
, but how can one tell the type of the object created by the new
expression at compile-time? (Emphasis is meant to stress the fact that I am not talking about the pointer returned by the new
expression, but rather about the array object created by the new
expression).
This is what Paragraph 5.3.4/1 of the C++11 Standard specifies about the result of a new
expression:
[...] Entities created by a new-expression have dynamic storage duration (3.7.4). [ Note: the lifetime of such an entity is not necessarily restricted to the scope in which it is created. —end note ] If the entity is a non-array object, the new-expression returns a pointer to the object created. If it is an array, the new-expression returns a pointer to the initial element of the array.
I used to think that in C++ the type of all objects is determined at compile-time, but the above example seems to disprove that belief. Also, per Paragraph 1.8/1:
[...] The properties of an object are determined when the object is created. An object can have a name (Clause 3). An object has a storage duration (3.7) which influences its lifetime (3.8). An object has a type (3.9). [...]
So my questions are:
It would be great if anybody could elaborate at least on one of the above points.
EDIT:
The Standard seems to make it clear that the new
expression does indeed create an array object, and not just several objects laid out as an array as pointed out by some. Per Paragraph 5.3.4/5 (courtesy of Xeo):
When the allocated object is an array (that is, the noptr-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. [ Note: both
new int
andnew int[10]
have typeint*
and the type ofnew int[i][10]
isint (*)[10]
—end note ] The attribute-specifier-seq in a noptr-new-declarator appertains to the associated array type.
The terms 'static type' and 'dynamic type' apply to expressions.
static type
type of an expression (3.9) resulting from analysis of the program without considering execution semantics
dynamic type
<glvalue> type of the most derived object (1.8) to which the glvalue denoted by a glvalue expression refers
Additionally, you can see that a dynamic type only differs from a static type when the static type can be derived from, which means a dynamic array type is always the same as the expression's static type.
So your question:
but how can one tell the type of the object created by the new expression at compile-time?
Objects have types, but they're not 'static' or 'dynamic' types absent an expression that refers to the object. Given an expression, the static type is always known at compile time. In the absence of derivation the dynamic type is the same as the static type.
But you're asking about objects' types independent of expressions. In the example you give you've asked for an object to be created but you don't specify the type of object you want to have created at compile time. You can look at it like this:
template<typename T>
T *create_array(size_t s) {
switch(s) {
case 1: return &(*new std::array<T, 1>)[0];
case 2: return &(*new std::array<T, 2>)[0];
// ...
}
}
There's little special or unique about this. Another possibility is:
struct B { virtual ~B() {}};
struct D : B {};
struct E : B {};
B *create() {
if (std::bernoulli_distribution(0.5)(std::default_random_engine())) {
return new D;
}
return new E;
}
Or:
void *create() {
if (std::bernoulli_distribution(0.5)(std::default_random_engine())) {
return reinterpret_cast<void*>(new int);
}
return reinterpret_cast<void*>(new float);
}
The only difference with new int[]
is that you can't see into its implementation to see it selecting between different types of objects to create.