Unsigned types are DANGEROUS??

P

Peter Remmers

Am 15.03.2011 19:17, schrieb Paul:
Noah Roberts said:
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 array identifier carries the information about the array's number of
elements and their type. A pointer to one of those elements does not. If
you have a recent Microsoft compiler at your disposal, take a look at
how _countof() is implemented, which returns the number of elements in
array. It uses some template magic to deliberately fail at compile-time
if you try to pass it a pointer instead of a real array identifier.

The difference between an array and a pointer can't be any more obvious.

Peter
 
P

Paul

Noah Roberts said:
I don't see what your confusion is. If the standard states:
"A name is a use of an identifier (2.10) that denotes an entity"
then with:

type* p_name = new type[16];

p_name is the name of the entity, that is the array.

The confusion is there. The entity that p_name identifies in this case is
a pointer, NOT the dynamically created array. Proof of point:
The entity is an array, you refuse to acknoweldge the arrays existence now.

type * p_name = new type[16];
type name;
p_name = &name;

You can't do that with arrays.

Your code doesn't do anything with the array, you simply re-assign to the
identifier. What are you trying to demonstrate?
No, the *entity* is. Pointers are entities.
The entity in this case is an array, again you do not acknowledge the full
expression, You are omitting the fact that an array exsits here.

And the name forms an identifier.


Because it's simply the case that it is true.
An array identifier is a pointer, thats how I see it . You obviously see it
differently so I can'[t be bothered arguin gwith what I consider idiot
opinions.

Basically it comes down to this:
You think an array index can never be negative.
I think an array index can be negative.

I would like to conclude this discussion with those two different opinions.
I trust most people will be able to understand who's opinion is most
narrow-minded and restrictive, unadabtable etc etc.

shrugg.
 
N

Noah Roberts

Noah Roberts said:
On 3/15/2011 11:35 AM, Paul wrote:

I don't see what your confusion is. If the standard states:
"A name is a use of an identifier (2.10) that denotes an entity"
then with:

type* p_name = new type[16];

p_name is the name of the entity, that is the array.

The confusion is there. The entity that p_name identifies in this case
is a pointer, NOT the dynamically created array. Proof of point:
The entity is an array, you refuse to acknoweldge the arrays existence
now.

type * p_name = new type[16];
type name;
p_name = &name;

You can't do that with arrays.

Your code doesn't do anything with the array, you simply re-assign to
the identifier. What are you trying to demonstrate?
The fact that the identifier is a pointer goes without saying ,

No, the *entity* is. Pointers are entities.
The entity in this case is an array, again you do not acknowledge the
full expression, You are omitting the fact that an array exsits here.

A pointer to an array is not an array; it is a pointer.

Equally important to note here is that the pointer in question in these
cases is NOT a pointer to an array. These are pointers to 'type'. They
point to an object of type 'type'. That object happens to be a part of
an array.

A pointer to an array would have a type something like so:

int (*)[10]

More important things to note about the whole conversation:

int * ptr = new int[10];
++ptr; // yay! Now I can use negative subscripts on this "array
identifier"!!! HAHAHAHA!!!

delete [] ptr; // OH.

Probably the most important thing of note here though is that Paul is
simply never going to admit, possibly will never even realize, that he's
in error.
 
P

Paul

Peter Remmers said:
Am 15.03.2011 19:17, schrieb Paul:
Noah Roberts said:
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.
What do you mean by , " it only gives indirect access"?
It's the only way to access the array, at all.
The array identifier carries the information about the array's number of
elements and their type. A pointer to one of those elements does not.
If you have a recent Microsoft compiler at your disposal, take a look at
how _countof() is implemented, which returns the number of elements in
array. It uses some template magic to deliberately fail at compile-time if
you try to pass it a pointer instead of a real array identifier.

The difference between an array and a pointer can't be any more obvious.
What you mean is the difference between an array-type and pointer-type,
can't be more obvious.

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);
}

This does not mean the following is not an array:
int* arr1 = new int[16];
++arr1;

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?

Playing word games can work both ways, example:
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?

It's up to you how you want to look at it, I think my views are quite clear,
and I'm happy with my view on the subject.
 
J

James Kanze

On 3/14/2011 3:52 PM, James Kanze wrote:
Well, luckily for me neither I nor most of the people I've ever worked
with are "experts" and so we're completely free to disagree with all the
gods, their saints, and wanna-be bishops.

Nobody said you have to agree; in fact, I explicitly said that
there were arguments on both sides. On the other hand, I don't
agree with characterizing the ideas of people like Stroustrup as
"plain idiocy".
 
J

James Kanze

James said:
On Mar 13, 2:07 am, "Alf P. Steinbach /Usenet" <alf.p.steinbach
(e-mail address removed)> wrote:
[..,]
Not in the sense that you're apparently asking about, that is,
there is not anything broken about e.g 'unsigned' itself. But
as part of a willy-nilly broken type hodge-podge inherited
from C, yes, it's broken. That's because implicit conversions
that lose information are all over the place.
I think that's the best explination I've seen to date. It's not
unsigned per se which is broken, it's the whole way integral
types interact (and implicitly convert) which is broken. (This
is why most of the real experts, starting with Stroustrup, use
int unless really forced to do otherwise.)
By "real experts" you of course mean "language lawyers".

By "real experts", I mean the people who designed the language
to begin with, or who know it well. People who are concerned
with practical solutions---C++ was designed to be a practical
language, not a theoretical one.
 
J

James Kanze

James said:
On Mar 13, 2:07 am, "Alf P. Steinbach /Usenet"<alf.p.steinbach
(e-mail address removed)> wrote:
[..,]
Not in the sense that you're apparently asking about, that is,
there is not anything broken about e.g 'unsigned' itself. But
as part of a willy-nilly broken type hodge-podge inherited
from C, yes, it's broken. That's because implicit conversions
that lose information are all over the place.
I think that's the best explination I've seen to date. It's not
unsigned per se which is broken, it's the whole way integral
types interact (and implicitly convert) which is broken. (This
is why most of the real experts, starting with Stroustrup, use
int unless really forced to do otherwise.)
By "real experts" you of course mean "language lawyers".
The consensus of the "real experts" was to make std::array::size_type a
typedef of .. wait for it .. std::size_t (an unsigned integral type); go
figure.

And why is size_t unsigned? I don't remember reading any papers
by you in the C committee when the decision was made.
 
J

James Kanze

Although I agree that Kanze far to often relies on argument by
authority,

When have I ever presented an argument by authority? The only
thing I'm arguing about here is the categorization of people
like Stroustrup as idiots.
and can be more than a little arrogant (only those agreeing
are "experts", dismissing other experts like Alexandrescu as academics)

First, I specifically said that this is an issue about which
experts may disagree. The majority that I've seen do use int,
but not all. (As for Alexandrescu, I've actually discussed the
issue with him in the past. He was even sort of half-way
convinced; at least, he saw the problems with unsigned. I don't
know what his current position is, however.)
but I can't say I understand your distinction between "language lawyers"
and "application programmers". It seems to me that, for good or bad, a
C++ developer really needs to be both.

You can't understand C++ without some "language lawyering", but
it's designed to be an application language, not a theoretical
one. Stroustrup's main concern was always usability, not some
abstract theoretical considerations.
 
J

James Kanze

How long is the passage where he opines thusly? A sentence? A paragraph?
A page? A chapter? Can you give the page number(s) please? As I was not
convinced by this thread or the links in it to change my style, I would
like to see if I find his reasoning any more compelling. (Your current
line of reasoning seems like "appeal to authority", BTW).

He doesn't opine. He just does. In the examples in the book,
even when the type is something like a size, which can't be
negative, he uses int.

I've given up arguing one way or another. If I'm asked, I'll
express my opinion. (But where I'm working, the decision was
made before I arrived.) And there are legitimate experts on
both sides. (None of the solutions is ideal, given what C++ is
and what it has inherited from X.) What I haven't given up on
is objecting when people characterize the legitimate experts as
idiots, or suggest that they'd be better off with Java.
 
N

Noah Roberts

The consensus of the "real experts" was to make std::array::size_type a
typedef of .. wait for it .. std::size_t (an unsigned integral type); go
figure.

Do you know why though? This can be as much an historical artifact as
any purposeful design. C uses unsigned types for a lot of functions. C
has been around for decades, during which time much has been learned.
The C++ library also does a lot of things that later turned out to be
pretty bad mistakes; vector<bool> for example was, in hindsight (and
maybe some predicted such) a really stupid idea.

I no more agree that something should be done a certain way because the
standard library does it than that Stroustrup does it with one minor
addendum: if I'm interacting with the library I tend to do things its
way. The current argument doesn't impress me in the slightest one way
or the other. People who can't deal with the conversions that C++ does
for whatever reason are going to have hard times across the board.
People who can't write "assert(x >= 0)" likewise. People who don't
understand that you can't iterate lower than 0 or past the size of the
type without serious issues are going to have serious issues. People
who don't know how to cast to/from unsigned likewise. Practically
speaking, it's not a major issue that people should be freaking out this
much about.

I tend to use unsigned types to represent indexes and sizes (values that
must be non-negative by definition). If you can't write your looping
code to correctly check against size() then, quite frankly, you're
pretty damn green. I don't feel the story is much different when people
use signed types. You have to be careful in *different ways* when you
pick one over the other. No big deal and no major difference either way.

Frankly speaking, from real application domain development I can't
really think of the last time I found a bit field particularly
appropriate for anything. Almost every excuse for one should be
replaced with polymorphism. Thus I don't find that distinction very
useful but of course others, in different domains, will.

I do find it annoying when people don't correctly cast between them.
For example, I have to encase a vast number of boost headers within
pragma statements because I do what everyone should be doing: compile
with full warnings and error on warning. A great majority of these are
necessary but more than a few are simply due to constructs such as "for
(int i = 0; i < vect.size(); ++i)". Putting a static_cast in there to
rid your code of warnings is neither a big deal nor does it alter the
output (the cast happens anyway).

In the end there's enough people on both sides of the fence (it's FAR
from single sided as Kanze implies with "most experts") that you'd damn
well better be able to work with either if you want to succeed. You
also need to be able to question the standard library, those who wrote
it, and any other authority you might tend to defer to. Even experts
are prone to serious mistakes, misconceived opinions, and days of utter
stupidity. Since everyone is capable of learning, nobody is free from
the responsibility. I've changed my mind before, I will again. So has
Stroustrup, Sutter, Alexandrescu, etc... I pointed out a slicing error
(newbie mistake) to Meyers once at a lecture he had, does that mean he's
not an expert? I certainly wouldn't say so.

In short, in my not particularly humble opinion...who really gives a
****? Not me. It's not a major thing. Certainly not as big a deal as
its been made of here (although the failure to distinguish between
pointers and arrays bit has been rather humorous).
 
N

Noah Roberts

You are failing to recognize that there is a difference between examples
presented in books and what a programmer actually writes when cutting
real production code. I never characterized any "expert" as an idiot; I
said eschewing unsigned integral types in C++ is idiotic.

As much as I hate to, I have to agree with Kanze on this one. Many of
the people here have given good, reasonable reasons for "eschewing"
unsigned types. That's not idiotic and it's pretty short sighted (read:
idiotic) to simply discard it as such. That you don't agree with the
reasons is clear but its clearly more intelligent to recognize them AS
reasons.

If the reasons where stupid (and there's been quite a bit of that too),
you'd have a point. They're not. I personally don't think their
reasons are any more or less convincing than the opposing points, but
their reasons are sensible. You might say that calling unsigned types
"dangerous" is a bit extreme, but you can't deny that the issues that
have been brought forward are not real issues.
 
N

Noah Roberts

This does not mean the following is not an array:
int* arr1 = new int[16];
++arr1;

You are correct, none of the code you provided means that the above two
expressions are not an array. You've repeatedly sidestepped the point.
The point of the matter is that there are very clear definitions to
the words you are using incorrectly.
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?

Playing word games can work both ways, example:
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?

Pedantically, yes, but it's not an important distinction.

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?

Yes, and in this case the distinction IS important. The obviousness of
that importance is quite well illustrated by your confusion.
It's up to you how you want to look at it, I think my views are quite
clear, and I'm happy with my view on the subject.

Redefining standard terms doesn't do anything but confuse the issue. If
you are happy with using terms incorrectly, that's fine. You're not
going to be understood though. This was my whole point when I first
tried to explain where your problem was. You and Leigh where not
agreeing to terms and Leigh was using them more "correctly" than you
where (correctly in that they agree with the language of the standard).

One is always free to call the sky "fish". When you start talking about
"fish" though and people start to disagree with you (I've never heard of
a fish with clouds in it), it's not reasonable to start freaking out and
its especially not reasonable to insist that your statements are clear
(maybe by "clear" you mean vague and apparently erroneous). It is true
that essentially you're as right as anyone else, but that doesn't
actually mean anything in the slightest.
 
S

SG

I don't see what your confusion is. If the standard states:
"A name is a use of an identifier (2.10) that denotes an entity"
then with:

type* p_name = new type[16];

p_name is the name of the entity, that is the array.
The above expression creates an array, you seem confused about
this, similarly to Leigh and Noah.
Do you think this is not array?

What exacly? p_name? p_name denotes a pointer variable. You
initialized this pointer to store the address of the first element of
a dynamically allocated array.
The fact that the identifier is a pointer goes without saying,

Does it? I honestly can't tell what things go without saying and what
not when it comes to "discussing" something with you. btw: To be very
precise: The identifier *denotes* a pointer variable. An identifier is
a sequence of characters in your source code file.
as does the
fact that its name is p_name. The entity is an array structure,

The entity whose name is p_name is a pointer variable. Period. You can
use this pointer to access the elements of your dynamically allocated
array, yes. But the "entity" that the standard is talking about w.r.t.
the identifier "p_name" would be the pointer variable. The array you
created has no name. It is created by the new operator which returns
just an address.
[...] why I don't understand.

Might I ask what book(s) you used to learn C and/or C++?

SG
 
N

Noah Roberts

Also consider this c++0x code:

for (auto i = v.size(); i-- > 0;) // v is a std::vector
foo(v);

which IMO is superior to your favoured alternative:

for (int i = v.size() - 1; i >= 0; --i) // v is a std::vector
foo(v);

In practice I would probably use reverse_iterator (another example of
how example code can differ from production code).


I find the second version more clear. Clarity is my primary measure of
superiority. I'd be sure to cast though.
 
G

Garrett Hartshaw

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.
What do you mean by , " it only gives indirect access"?
It's the only way to access the array, at all.
The array identifier carries the information about the array's number of
elements and their type. A pointer to one of those elements does not.
If you have a recent Microsoft compiler at your disposal, take a look at
how _countof() is implemented, which returns the number of elements in
array. It uses some template magic to deliberately fail at compile-time if
you try to pass it a pointer instead of a real array identifier.

The difference between an array and a pointer can't be any more obvious.
What you mean is the difference between an array-type and pointer-type,
can't be more obvious.

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);
}

This does not mean the following is not an array:
int* arr1 = new int[16];
++arr1;

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?

Playing word games can work both ways, example:
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?

int x; /* x is an integer */
int * p = &x; /* p is a pointer to an integer */
int a[3]; /* a is an array of 3 integers */
int * pa = a; /* pa is a pointer to an integer */
int * dx = new int(); /* dx is a pointer to an integer */
int * da = new int[3]; /* da is a pointer to an integer */

Because 'pa' and 'da' both point to the first element of an array, it
is well defined to do pointer arithmatic on them as long as you stay
within the bounds of the underlying array (e.g 'pa[1]' which is
equivalent to '*(pa + 1)'). With 'a', 'a[1]' is again equivalent '*(a
+ 1)'. However, since a is actually an array, a is implicitly
converted to type int* before operator+ can be applied, so it is
equivalent to '*((int*)a + 1)'.
 
P

Peter Remmers

Am 15.03.2011 21:14, schrieb Paul:
Peter Remmers said:
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.

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.
What do you mean by , " it only gives indirect access"?
It's the only way to access the array, at all.

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.

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".

What you mean is the difference between an array-type and pointer-type,
can't be more obvious.

If two objects have a different type, they can't be the same object...
nor can one object be the identifier of the other.
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]

is this:

sizeof:4 typeinfo:pi
sizeof:64 typeinfo:A16_i
sizeof:4 typeinfo:pi

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.
Playing word games can work both ways, example:

We're not playing word games. The terms "identifier", "name", "object",
and "array" etc. are clearly defined by the standard.
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. 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.
It's up to you how you want to look at it, I think my views are quite clear,
and I'm happy with my view on the subject.

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.

Peter
 
J

James Kanze

"Understatement of the year"! Everyone seems to be advertising
their pet examples as to why it should be one way or the other
instead of doing a wholistic examination of the issue.

Yes. Technically, I personally find the arguments against
unsigned convincing. But not overwhelmingly so, and I can
easily understand the other side. In fact, IMHO, the technical
arguments on either side are so underwhelming that they don't
outweigh the non-technical arguments.
But when they graduate from being C++ experts and into the realm of
application domain coding, will they still do the same? (I couldn't
resist!).

Apparently. I was a contractor for many, many years; I've
worked in a lot of different places (in different domains---I'm
a telecom's specialist, but I currently work in an investment
bank). And I can't think of a single case where the rule wasn't
int, unless there are strong technical reasons otherwise. That
seems to be the general attitude. In most cases, I'm sure,
without ever having considered the technical aspects. One
learns C++ from Stroustrup, and Stroustrup uses int everywhere
(without ever giving a reason, as far as I know---I suspect that
he does so simply because the people he learned C
from---Kernighan, in particular) did so.
A list of ALL the cases would be good to create. Everyone seems to have
their pet example, so why not put them and more in one place for once and
for all. What a better place to do that then this ng!

You don't need a list. The fundamental problem is: what do you
do when signed and unsigned meet. Generally, when two types
meet in an arithmetic expression, the one with the smaller range
is converted to the one with the larger range. The problem with
unsigned/int is that the range of one is not a subset of the
range of the other. So you have four possibilities:
-- convert both to signed,
-- convert both to unsigned,
-- convert both to some larger type, whose range is a superset
of both of there ranges.
-- declare the operation illegal without an explicit cast.
All things considered, I think that the last choice would be the
best. But it certainly doesn't fit into the philosophy of C,
and by the time the C committee was discussing standardization,
would have broken who knows how much existing code. The third
also sounds nice, until you realizde that there may not be some
larger type---on a 32 bit machine, both int and long are 32
bits, and back then, there was no long long. Historically, most
C compilers implemented the first; the C committee, after an
enormous amount of discussion, chose the second. With the
recognition that it also had problems.

size_t underwent similar discussions. The absolute requirement
was that it could represent the size of any object which you
could define in C. Which meant, on the 32 bit machines of the
day (and without long long), unsigned long (which was the same
as unsigned int). Short of making a C implementation impossible
on the VAX (the most widespread implementation of the day), they
had to allow size_t to be unsigned. And given the problems
which occur if you don't even know if a type is unsigned or not,
they preferred requiring unsigned to making it implementation
defined.

Anyway, as mentionned above, the "killer" argument, if there is
one, is not technical, but rather what the average, everyday C++
programmer understands when he sees the type. (Of course, if
you don't care about the readability of your code, it's not a
killer argument at all.) And for whatever reasons, most C++
programmers learn, directly or indirectly, from Stroustrup.
Who, in his most recent book, doesn't mention unsigned until (as
far as I can tell) page 919, when he presents bitwise operators.
And where he refers to §25.5.3, where at one point he says:

So far, we have just used signed integers (e.g. int). A
slightly better set of rules would be:
-- Use signed integers (e.g. int) for numbers.
-- Use unsigned integers (e.g. unsigned int) for sets
of bits.

People read this, and live by it; when most C++ programmers see
"unsigned", they assume "sets of bits". Especially as earlier
(page 280, for example), he has examples like:

for (int i = 0; i < v1.size(); ++ i)
// ...

, where v1 is an std::vector.

All of which, IMHO, puts the burden of proof on those arguing in
favor of unsigned. Unless there are really strong technical
arguments in favor of unsigned (and I've yet to see really
strong technical arguments either way), readability says go with
the crowd.
 
J

James Kanze

[...]
There is the option to avoid "brain-damaged" language constructs
altogether, which no one has brought up. Of course if that is not
practical, then maybe the language is based upon weak foundation and
transition should be the goal. Something's gotta give.

Yes. Let's avoid brain-damaged language constructs entirely.
Of course, that means not using C++. Nor Java, nor C#, nor any
other language in the C family. Nor Ada, nor anything else
derived from Pascal. We'll just have to define our own
language, from scratch. And not let it evolve, or actually be
used for anything. The last will be easy, because there won't
be a compiler for it either.

In the end, C++ isn't really a very good language at all. It's
just that all of the others available are even worse.
 
M

MikeP

James said:
He doesn't opine. He just does. In the examples in the book,
even when the type is something like a size, which can't be
negative, he uses int.

I wonder if he's ever tried the other way. I think I remember consciously
making the decision when I was still doing C and that it did have a
permeating effect but that it all just automagically works out and
haven't really looked back since there were no compelling arguments to do
so.
I've given up arguing one way or another.

I think they may be equally valid but I started down the track of probing
for the underlying problem, as in "how could this situation be fixed if
starting with a clean slate". "Everyone" just seems to want to grab a
splinter of the issue and promote it as some kind of final word on it. I
think the mindset is a key. Some mechanics love their tools and toolboxes
others just like fixing and building cars.
If I'm asked, I'll
express my opinion. (But where I'm working, the decision was
made before I arrived.) And there are legitimate experts on
both sides. (None of the solutions is ideal, given what C++ is
and what it has inherited from X.) What I haven't given up on
is objecting when people characterize the legitimate experts as
idiots, or suggest that they'd be better off with Java.

Internet is volatile.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads


Members online

Forum statistics

Threads
473,780
Messages
2,569,611
Members
45,277
Latest member
VytoKetoReview

Latest Threads

Top