Peter Remmers said:
Am 15.03.2011 21:14, schrieb Paul:
message
Am 15.03.2011 19:17, schrieb Paul:
The important, practical consequence is that array size information
is
lost as soon as the array identifier is converted into a pointer.
You
can't even get it back when the information is still available to
the
compiler:
int arr[] = {1,2,3};
int * p = arr;
sizeof(arr) == 12
sizeof(p) == 4
With your interpretation a dynamic array is not an array, which is
obvioulsy
incorrect.
An array created by 'new' is an array that has no name. Just like with
everything that is dynamically created by new, there is no identifier
that
directly identifies the object created on the heap. All you get is a
pointer to the object which must be stored in a pointer variable that
you
have to provide. That pointer is not the array itself. It is a
different
object, with its own identifier and its own region of storage. This is
obvious if you consider what sizeof() returns for the two.
Consider this:
new int[3];
This statement does not contain any identifiers, and yet an array has
been
created on the heap. And because the pointer that new returned was not
saved, the array is leaked. There is just no way to get hold of the
array
without an identifier. A pointer only gives you indirect access to the
array.
The pointer is the arrays identifier.
No, it's not. An identifier is just a string of characters in the source
code - a compile-time entity. The pointer value returned by new is a
run-time entity. This value is stored in a pointer variable, which has an
identifier, an address (possibly in a completely different storage type as
the array), and a value (the address of the array's first element) which
is of course different from its own address.
This is just another example of word games the identifier is arr in
following:
int* arr = new int[16];
Yes its a pointer but it s a pointer to an array. And, as it's the only
identifier we have for the array, it's the arrays' idientifier.
A entity withiout an identifier is not a useable entity.
That pointer must be treated like an array, by this i mean you cannot
re-assign it an address of simple integer:
int x;
arr = &x;
This is wrong you unless you have previously taken all precautions to assign
the array to a new identifier, or you don't care about losing it. As soon as
you lose the pointer you lose the array because the pointer is the
identifier for that entity, or if you prefer exact standardesque it might
be... The identifier for the pointer is also the identifier for the array.
Do you think we should consider a dynamic array an unidentified entity? I
don't I think they are identifiable by the pointer returned from new, this
seems pretty logical to me.
If you disagree with the above please provide a *reasonable* argument why.
Not state the obvious fact that the identifier for the array is actually a
pointer.
Or suggest that I don't know what an identifier means in any sense of the
word , it was me who introduced the word to the discussion.
int arr[10];
int *p1 = &arr[0];
int *p2 = new int[10];
Here, p1 and p2 are completely equivalent in that they both are pointers
to int, and that they both point to the first element of a (each a
different) array of 10 ints. The difference is the way the respective
array has been created. p1 points to an array in automatic storage. p2
points to an array in dynamic storage. The array p1 points to has a name -
embodied by the identifier "arr". p2's array does not have a name and so
there is no identifier.
I disagree, the identifier p2 is the only identifier we have for the array
therefore it is the identifier for both pointer and array. See above
explanation.
It's nonsensical to suggest the array has no identifier, when it does.
Im the example above, p1 and p2 only provide indirect access because they
are distinct objects of pointer-type that only point to an array, but they
are not the array itself. In the case of p1, "p1" gives indirect access,
"arr" is direct access. For p2, there is no direct access because the
array does not have a name, and so p2 is the only (indirect) means of
access.
All memory is accesssed via a pointer address, thats just how computers
work. In this case p2 is the name we have to identify the array, so it does
have a name.
If I have a piece of paper with a picture of Paul on it, would you say the
paper *is* Paul himself? It is just a picture of Paul. The
4-character-string "Paul" is the identifier that represents the name of
Paul. If I name my piece of paper "Judy", "Judy" is an identifier that
represents the name of the Picture. "Judy" certainly is not an identifier
for Paul, and the piece of paper is even less so.
If I give you a picture of a person you don't know, then to you, that
person does not have a name, and you can not directly refer to that person
by their name, but only indirectly as "the person on that picture" ("the
array that the pointer points to"). If I happen to know that the person's
name is "Jerry", I can say "Jerry's hair is black", while you can only say
"The color of the hair of the person on that picture is black".
Show me how to pass an array to a function without giving the array a name.
I bet you can't do it, you need an identifier.
Would this suggest dynamic arrays cannot be passed to functions, I think not
because we can pass identifiers, which in this case happen to be pointers.
If two objects have a different type, they can't be the same object... nor
can one object be the identifier of the other.
Here you use identifier as if it's an object, but you were fast to correct
me earlier by stating it is just a string of characters in source code. Back
to the word games again.
An identifer for one object can also be the identifier for another object.
Who says an identifier can only identify one object?
An array can be considered a contiguous block of different objects,
therefore any array identifier identifies numerous objects.
I think what you are trying to explain is the following:
#include<iostream>
typedef int t_arr16[16];
void foo1(int* par){
std::cout<< "sizeof:"<< sizeof(par)<< "\t typeinfo:"<<
typeid(par).name();}
void foo2(t_arr16& par){
std::cout<< "sizeof:"<< sizeof(par)<< "\t typeinfo:"<<
typeid(par).name();}
int main(){
t_arr16 arr1 ={0};
std::cout<< "Calling foo1: ";
foo1(arr1);
std::cout<< std::endl<< "Calling foo2: ";
foo2(arr1);
}
That works because an array variable can be implicitly converted to a
pointer to its element type.
Try this:
int *p = &arr1[0]; // or int *p = arr1;
foo1(p); // OK
foo2(p); // error
The output I get for
foo1(arr1); // implicit conversion from int[16] to int*
foo2(arr1); // passed as reference
foo1(p); // p is already int*
//foo2(p) error: int* cannot be converted to int(&)[16]
I was posting the code to support your argument, that static arrays can
carry information, and array-types are different from pointer-types.
is this:
sizeof:4 typeinfo
i
sizeof:64 typeinfo:A16_i
sizeof:4 typeinfo
i
Different sizes, different types, different objects.
Of course, foo2's "par" is just an alias for the array and not the array
itself, because it is a reference type - for which we now that the
compiler most likely just uses a masqueraded pointer. It does not actually
pass those 10 integers by value.
This does not mean the following is not an array:
int* arr1 = new int[16];
++arr1;
It means that arr1 is a pointer, initialized with the address of the first
element of some unnamed integer array on the heap, and then its value is
changed to be the address of the second element of that array.
And it doesn't suggest an array must always have zero based indexing. The
C++ standard specifically states the rules about array indexing and its
clear that C++ allows non-zero based indexing.
What possible reason, even in the most idiotic minds, would there be to
restrict the language in such a way?
int arr1[10];
If you access the array's elements via the "arr1" identifier, you can't
use a negative index because that would be UB because your access would be
out of range. That's because "arr1" can only ever be converted to a
pointer to the *first* element (the one with the index zero) of the array.
arr1 connot be assigned to point to something else, say the second
element, because it *is not* a pointer whose value can be changed. It can
conly be *converted* to a pointer.
int *p = &arr1[1];
If you create a pointer variable, you can have it point anywhere you want,
for example somewhere in the middle of arr1. You can then use positive or
negative indices as offset to that pointer base, as long as you don't try
to access something that is not backed up by some object's storage. Of
course, interpreting the data you read from that address as an int may
still be UB.
How is it undefined behaviour?
An array is guaranteed to be a contiguous block, its completely defined in
C++ to create a non zero based array.
int* arr= new int[16];
/*Assume allocation succeeded*/
++arr;
arr[-1]=64;
arr[-1] is guaranteed to yield the first element of the array. It's not UB,
it's completely defined.
We're not playing word games. The terms "identifier", "name", "object",
and "array" etc. are clearly defined by the standard.
So can you tell me where the standard defines that these "names" or
"identifiers" cannot refer to more than one "object" or "entity"?
int x;
The actual integer object is just a a piece of memory, x is just an
identifier. So are we wrong to say x is an integer? Likewise:
int* arr = new int[16];
The actual array object is just a piece of memory, arr is just an
identifier. So are we wrong to say arr is an array?
I agree that in a programmer's everyday language, one could say "I create
a dynamic array 'arr' of 16 integers". But that does not mean that you can
close your eyes to the fact that formally, and in reality, "arr" is just a
pointer to an integer that is initialized to point to the first integer
element of some unnamed array in dynamic storage.
Of course its wrong to close your eyes to this fact, but it is even more
wrong to close your eyes to the fact that it's primarily an array.
The biggest entity here is the array , the pointer is just an intermediate
object used to identify the array. You seem to be trying to shift the foucs
so as the pointer is the the main entity, when it's not.
It's just that the formal laguange is too verbose to use it all day long.
So we use the formally incorrect short forms, where everybody knows what is
meant by it, but where also everybody knows that it is not completely
correct.
But most of the things we say is correct. You are interpreting correctnesss
as meaning "used in the same context as the standards".
Yes the standard is a refernece which defines the language and is therefore
the rules, but it is written in a context that must be interpeted correctly.
If I say, with:
int x =5;
x is an integer.
If someone "corrected" me by saying no that not strictly true because its
actually a sequence of characters, they are the ones who are incorrect for
misinterpreting(deliberately or otherwise) the context of the statement,
IMO.
I trust you will agree with the above, as it seems preety much common sense.
Now if I say an array can have a non zero based index as per:
int* arr = new arr[16];
arr++;
If someone says that's not an array it's a pointer they are incorrect
because it's both a pointer and an array.
The C++ language is defined in such a way that it has the flexibility to do
this, if not I think its userbase would be a fraction of it's size. Can you
imagine what a shitty language it would be if we couldn't even create a non
zero based array, I would drop it like a brick.
I agree that you could say "foo::bar() is a member function of xyz", where
xyz is some object of class-type foo. I use such informal speech myself,
and I admit that you can get pretty far with such a point of view. But I
do keep in mind that formally, foo() is a member of xyz's class, because
that's what it really is behind the scenes. And if it comes to corner
cases, and you don't have to go very far, these details become apparent.
Back to the old member function thing , hmm.
foo::bar() is a class scope expression, this does not imply any object.
An object is:
foo f;
An member function that is part of such object is :
f.bar();
I can see it both ways too, but I don't distinctly see one as correct and
the other is not correct, both are correct in their given context.
What is incorrect is to suggest that all member functions are members or a
class but not members of an object of that class type. As obviously this
only applies to static member functions.
Can you imagine what a shitty language it would be if we couldn't have
member functions for objects? It certainly wouldn't be an OOP language in
any sense of the term.