sizeof dinamically alocated array....

M

Martin Vejnar

Phlip said:
AnonMail2005 wrote:

v.begin () and v.end (), of course are valid. But you can't
dereference (i.e. access) v.end (). And since v.begin () ==
v.end () for an empty vector, why would you think you could
derefernce v.begin () for an empty vector?
Try this:

assert(0 < v.size() || v.end() == v.begin()); // well defined?

assert(&v[0] == &*v.end()); // not always well defined?

assert(0 < v.size() || &v[v.size()] == v.end()); // always well defined?

So for an empty vector, v.end() == v.begin(), while v[0] is invalid because
v.end() is simply magic - there's no secret contained sequence that it's off
the end of.
The crux of the matter is when it is ok to _dereference_ an iterator.

Your first statement is just iterator comparison - they aren't
dereferenced - so it is safe.

It is not ok to dereference v.end () so *v.end () is not ok. Even if
you do this &*v.end(), so your second statement is not safe.

v[N] where N is an integer is _dereferencing_. So your third statement
is not safe. And neither is v[0] for an empty vector for same reason
as why it is not safe to dereference v.end ().
I should have added that your first statement never needs the size
check.

And your third statement is never safe even with the size check.

Please, do not top-post.

As I understand it, it is safe to have a _pointer_ to an element one
past the end of an array. Isn't it safe to have a _reference_ to the same?

If it is, then &v[0] should be ok, since vector's subscript operator
returns a reference.

Martin
 
M

Martin Vejnar

Tomás said:
If you define an array as follows:

char array[70];

Then the following expressions all have unique types:

1: array
Type: char[70]

2: &array
Type: char[70] *

The actual type is 'char (*)[70]'.
3: array[0]
Type: char

4: &array[0]
Type: char *

( I haven't taken modifiers into account, e.g. "const" )

Beginners tend not to see the distinction because 1, 2 and 4 can all
implicity convert to: char *.

'char (*)[70]' can most certainly not.
If we define an array of char's with "new", e.g.:

new char[5]

The type of the above expression is not: char[5] *

But rather: char *

Therefore, when calling "delete", it makes sense to give it an expression of
type: char *

rather than: char[5] *

which is why I employed "reinterpret_cast" in my initial post.

You're very lucky it worked.
Btw: do you think that the following assumption always holds?

assert(sizeof(char (*)[70]) == sizeof(char *));
 
M

Me

Vector is the way to go.

I have read in Meyers that &v[0] is not advisable unless v.size () > 0.

The *only* correct way is to use v.data(). Unfortunately, the 1998
standard wording was too general to allow funky implementations of
vector so the contiguous element guarantee wasn't there and neither was
the data function:

http://www.open-std.org/JTC1/SC22/WG21/docs/lwg-defects.html#69
http://www.open-std.org/JTC1/SC22/WG21/docs/lwg-defects.html#464

C++TC1 in 2003 fixed the contiguous issue and (I believe) TC2 will fix
the data issue. But that's not really helpful today so I'd suggest
either:

- edit your stl headers to include the data member (if your vendor
didn't do that already)
- write a global function data() that does &v[0] and use that
everywhere until vector::data is reasonably implemented
- use this expression v.empty() ? 0 : &v[0] (or do this in your global
data function if you really want to play it slow but safe).

But as a warning. On many vector implementations, if you haven't
inserted any elements yet, v.data() returns null. As stupid as it may
sound, some functions cannot take null pointers even if you pass it a
size of 0 (most functions in standard C are undefined if you do this).
 
P

Phlip

BTW your Xnews is not setting your encoding properly; the a in your name
comes up different on different newsreaders.
delete [] reinterpret_cast< char * > ( &str );

More than enough rope to shoot your foot off, huh? ;-)

Actually I could've just written:

Understand I didn't read the prior posts. I was just responding to the sight
of

- reinterpret_cast
- &
- delete
- char *
- and []

all in one line!

You are correct to wrap scary-looking things up (if you _must_ use them)
into smart typesafe wrappers.
DeleteArray(str1);

The next step here is either to put that into a destructor, so it follows
Resource Acquisition Is Initialization...

....or to refactor the code to not need all those clever-clever things.
 
P

Phlip

Martin said:
Please, do not top-post.
+1

As I understand it, it is safe to have a _pointer_ to an element one past
the end of an array. Isn't it safe to have a _reference_ to the same?

Yes, but...
If it is, then &v[0] should be ok, since vector's subscript operator
returns a reference.

I suspect we have learned that when .size() == 0, .end() might be magic, not
one-off-the-end, so there might be no 0-length controlled array to

So is this well-formed and well-defined?

int * p = new int[0];
assert(p == &p[0]);
delete[] p;

(And note that I decline to consider assert(false) as "well-defined". Abrupt
program termination without calling many destructors sounds very close to
undefined to me...)
 
M

Martin Vejnar

Phlip said:

I don't understand what that means.
As I understand it, it is safe to have a _pointer_ to an element one past
the end of an array. Isn't it safe to have a _reference_ to the same?

Yes, but...
If it is, then &v[0] should be ok, since vector's subscript operator
returns a reference.

I suspect we have learned that when .size() == 0, .end() might be magic, not
one-off-the-end, so there might be no 0-length controlled array to

True enough, see below.
So is this well-formed and well-defined?

int * p = new int[0];
assert(p == &p[0]);
delete[] p;

(And note that I decline to consider assert(false) as "well-defined". Abrupt
program termination without calling many destructors sounds very close to
undefined to me...)

Yes, it is.

Regarding the first line:
[5.3.4/7] 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.

So we have a valid pointer to an array. Regarding the second line, we
can modify '&p[0]' like this:

&p[0] === &(p[0]) === &(*(p+0)) == &(*p) === &*p

Up until now, everything is well-defined.

The question that arises is whether '&*p == p' for 'p' pointing to an
element one past the end of array. I couldn't find any relevant clause
(which doesn't mean that there isn't any, it merely shows my inability
to search. If you know where such a clause is, feel free to enlighten
me) in the Standard that would support my opinion, but AFAIK we're
allowed to refer to one element past the end of array, as long as we
don't try to access the value stored in that element.

Since we're not accessing the value (the * operator returns an lvalue,
the & operator accepts an lvalue, thus no lvalue-to-rvalue conversion
takes place), I believe that we are allowed to say '&*p == p'.

The problem with vector's [] operator is quite different. As I was
thinking about it, I realized, that my assuptions were wrong. '&v[n]',
where 'v.size() == n' is indeed undefined, as we do not know what really
happens inside operator []. (Unlike your int * example, where 'a' is
defined to be equivalent to '*(a+b)'.) The Standard only defines its
behavior for '0 <= n < size()'.

Martin
 
P

Phlip

I don't understand what that means.

It means one vote in favor of the statement.
Yes, it is.

So is assert(false); itself undefined? Is this undefined?

Up until now, everything is well-defined.

The question that arises is whether '&*p == p' for 'p' pointing to an
element one past the end of array. I couldn't find any relevant clause
(which doesn't mean that there isn't any, it merely shows my inability to
search. If you know where such a clause is, feel free to enlighten me) in
the Standard that would support my opinion, but AFAIK we're allowed to
refer to one element past the end of array, as long as we don't try to
access the value stored in that element.

If you can't find it, I certainly won't be able to!
Since we're not accessing the value (the * operator returns an lvalue, the
& operator accepts an lvalue, thus no lvalue-to-rvalue conversion takes
place), I believe that we are allowed to say '&*p == p'.

That sounds good enough!
The problem with vector's [] operator is quite different. As I was
thinking about it, I realized, that my assuptions were wrong. '&v[n]',
where 'v.size() == n' is indeed undefined, as we do not know what really
happens inside operator []. (Unlike your int * example, where 'a' is
defined to be equivalent to '*(a+b)'.) The Standard only defines its
behavior for '0 <= n < size()'.


Ah, so v[n] doesn't follow the same off-the-end rules as raw vectors or
iterators.

In summary: Write stupid code that obviously works, and use v.size() > 0 to
defend &v[0].
 
A

AnonMail2005

Phlip said:
I don't understand what that means.

It means one vote in favor of the statement.
Yes, it is.

So is assert(false); itself undefined? Is this undefined?

Up until now, everything is well-defined.

The question that arises is whether '&*p == p' for 'p' pointing to an
element one past the end of array. I couldn't find any relevant clause
(which doesn't mean that there isn't any, it merely shows my inability to
search. If you know where such a clause is, feel free to enlighten me) in
the Standard that would support my opinion, but AFAIK we're allowed to
refer to one element past the end of array, as long as we don't try to
access the value stored in that element.

If you can't find it, I certainly won't be able to!
Since we're not accessing the value (the * operator returns an lvalue, the
& operator accepts an lvalue, thus no lvalue-to-rvalue conversion takes
place), I believe that we are allowed to say '&*p == p'.

That sounds good enough!
The problem with vector's [] operator is quite different. As I was
thinking about it, I realized, that my assuptions were wrong. '&v[n]',
where 'v.size() == n' is indeed undefined, as we do not know what really
happens inside operator []. (Unlike your int * example, where 'a' is
defined to be equivalent to '*(a+b)'.) The Standard only defines its
behavior for '0 <= n < size()'.


Ah, so v[n] doesn't follow the same off-the-end rules as raw vectors or
iterators.

In summary: Write stupid code that obviously works, and use v.size() > 0 to
defend &v[0].

After consulting with my books I can tell you that Meyers' Effective
STL says to guard against doing &v[0] when size () == 0.

The Sutter/Alexandrescu book C++ Coding Standards does not mention this
but they cite the Meyers book as a relevant reference for this item.

And, the FAQ agrees with Meyers.
 
T

Tomás

The actual type is 'char (*)[70]'.


My bad.

..can all
implicity convert to: char *.

'char (*)[70]' can most certainly not.


*goes off and tries to compile it...*

Woops, you're right.

Btw: do you think that the following assumption always holds?

assert(sizeof(char (*)[70]) == sizeof(char *));


Aren't all pointers the same? Same alignment, same amount of bits.

We can use "void*" to store any sort of pointer... so it would make sense
if all pointer variables were the same.


-Tomás
 
B

Ben Pope

Tomás said:
Aren't all pointers the same? Same alignment, same amount of bits.
No.

We can use "void*" to store any sort of pointer... so it would make sense
if all pointer variables were the same.

A void* is large enough to store any pointer that can be implicitly
converted to void*.

Pointers to members are completely separate from void*.

Ben Pope
 
P

Phlip

Ben said:
Pointers to members are completely separate from void*.

Pointers to members differ so completely from pointers that they should not
be called "pointers". They should be called "smart offsets", or
"discriminants". Smart because they know if the target is virtual, offsets
because they know where in an object the target is, and discriminants
because they bind typesafely.

A pointer to member cannot be typecast.
 
J

Jerry Coffin

[ ... ]
Aren't all pointers the same? Same alignment, same amount of bits.

Not necessarily. Just for one example, on a Cray a normal
address is of a 64-bit word. C and C++ use 8 bits for
char and 64 bits for everything else. A pointer to
anything else is basically a raw address, but a pointer
to char is an address _plus_ 3 extra bits to specify a
byte inside of that word.
We can use "void*" to store any sort of pointer... so it would make sense
if all pointer variables were the same.

It's also guaranteed that void * and char * have the same
representation -- but that's about it. An int * can be
(and as mentioned above, on at least one type of machine,
is) different.
 

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

Members online

No members online now.

Forum statistics

Threads
474,432
Messages
2,571,682
Members
48,796
Latest member
Greg L.

Latest Threads

Top