contradiction in TC++PL?

E

ES Kim

Here's a code fragment from TC++PL Special Edition, p291:

void f1(T a)
{
T v[200];
T* p = &v[0];
p--; // please note (my comment)
*p = a; // oops: 'p' out of range, uncaught
++p;
*p = a; // ok
}

And here's an excerpt from p92:

"The result of taking the address of the element before the initial element
is undefined and should be avoided."

The author says, as I understand, it's ok with ++p after p--, which I think
contradict the statement in the excerpt. What do you think?
 
B

BekTek

Hi~
It's good to see you, you Korean right? me either..

Anyway,
"The result of taking the address of the element before the initial element
is undefined and should be avoided."
The author says, as I understand, it's ok with ++p after p--, which I think
contradict the statement in the excerpt. What do you think?

Both clauses are right IMHO.
p-- actually returns the fist element's reference even though it decreaments
internal pointer..
It's because that's posfix..
So in this case, there in no way to access the element before the zeroth
element..

And then '++p' makes the pointer point to the zeroth element..
T v[200];
T* p = &v[0];
p--; // please note (my comment)
++p;

So then, the code above is not dangerous..

Is that your questions?
:)

ES Kim said:
Here's a code fragment from TC++PL Special Edition, p291:

void f1(T a)
{
T v[200];
T* p = &v[0];
p--; // please note (my comment)
*p = a; // oops: 'p' out of range, uncaught
++p;
*p = a; // ok
}

And here's an excerpt from p92:

"The result of taking the address of the element before the initial element
is undefined and should be avoided."

The author says, as I understand, it's ok with ++p after p--, which I think
contradict the statement in the excerpt. What do you think?
 
E

ES Kim

BekTek said:
Hi~
It's good to see you, you Korean right? me either..

Yes, I'm a Korean. Nice to see you.
Anyway,


Both clauses are right IMHO.
p-- actually returns the fist element's reference even though it decreaments
internal pointer..
It's because that's posfix..
So in this case, there in no way to access the element before the zeroth
element..

And then '++p' makes the pointer point to the zeroth element..

I'm not sure what you mean by 'internal pointer'.
There's no difference between postfix and prefix form in this context.
The expression p-- is evaluated as a pointer to the initial element,
but it also has a side effect, which makes p point to the address before
the initial element.
 
A

Alf P. Steinbach

* ES Kim:
Here's a code fragment from TC++PL Special Edition, p291:

void f1(T a)
{
T v[200];
T* p = &v[0];
p--; // please note (my comment)
*p = a; // oops: 'p' out of range, uncaught
++p;
*p = a; // ok
}

And here's an excerpt from p92:

"The result of taking the address of the element before the initial element
is undefined and should be avoided."

The author says, as I understand, it's ok with ++p after p--, which I think
contradict the statement in the excerpt. What do you think?

According to Google it's not in the errata list.

Executing those statements in sequence is definitely Undefined Behavior,
and in particular the increment can not "fix" the earlier invoked UB.

Mail Bjarne and get the $30 prize money (or whatever the amount is... ;-)).
 
I

Ioannis Vranos

ES said:
Here's a code fragment from TC++PL Special Edition, p291:

void f1(T a)
{
T v[200];
T* p = &v[0];
p--; // please note (my comment)
*p = a; // oops: 'p' out of range, uncaught
++p;
*p = a; // ok
}

And here's an excerpt from p92:

"The result of taking the address of the element before the initial element
is undefined and should be avoided."

The author says, as I understand, it's ok with ++p after p--, which I think
contradict the statement in the excerpt. What do you think?


p--; produces undefined behaviour since it points to an invalid element.
This is allowed only for one past the end element of a sequence.

++p; reincrements the pointer and points to the first element. In this
place, p is again pointing to a valid element and in this state it is
well defined.
 
I

Ioannis Vranos

Alf said:
* ES Kim:
Here's a code fragment from TC++PL Special Edition, p291:

void f1(T a)
{
T v[200];
T* p = &v[0];
p--; // please note (my comment)
*p = a; // oops: 'p' out of range, uncaught
++p;
*p = a; // ok
}

And here's an excerpt from p92:

"The result of taking the address of the element before the initial element
is undefined and should be avoided."

The author says, as I understand, it's ok with ++p after p--, which I think
contradict the statement in the excerpt. What do you think?


According to Google it's not in the errata list.

Executing those statements in sequence is definitely Undefined Behavior,
and in particular the increment can not "fix" the earlier invoked UB.

Mail Bjarne and get the $30 prize money (or whatever the amount is... ;-)).


Actually there is not any book error, since it is stated that undefined
behaviour is invoked.
 
E

E. Robert Tisdale

ES said:
Here's a code fragment from TC++PL Special Edition, p291:

void f1(T a)
{
T v[200];
T* p = &v[0];
p--; // please note (my comment)
*p = a; // oops: 'p' out of range, uncaught
++p;
*p = a; // ok
}

And here's an excerpt from p92:

"The result of taking the address of the element before the initial element
is undefined and should be avoided."

The author says, as I understand, it's ok with ++p after p--,
which I think contradict the statement in the excerpt. What do you think?

Correct. It's a bad example. A better example might be:

void f1(T a) {
T v[200];
T* p = &v[0];
*p = a; // ok
p--; // undefined but works everywhere
*p = a; // run-time error: 'p' out of range
++p; // still undefined but works everywhere
*p = a; // undefined but works everywhere
}
 
A

Alf P. Steinbach

* Ioannis Vranos:
ES said:
Here's a code fragment from TC++PL Special Edition, p291:

void f1(T a)
{
T v[200];
T* p = &v[0];
p--; // please note (my comment)
*p = a; // oops: 'p' out of range, uncaught
++p;
*p = a; // ok
}

And here's an excerpt from p92:

"The result of taking the address of the element before the initial element
is undefined and should be avoided."

The author says, as I understand, it's ok with ++p after p--, which I think
contradict the statement in the excerpt. What do you think?


p--; produces undefined behaviour since it points to an invalid element.
This is allowed only for one past the end element of a sequence.

++p; reincrements the pointer and points to the first element. In this
place, p is again pointing to a valid element and in this state it is
well defined.

That is incorrect.

The result of the decrement is UB.

The result of incrementing that result is UB, not a "reincrement".
 
A

Alf P. Steinbach

* Ioannis Vranos:
Alf said:
* ES Kim:
Here's a code fragment from TC++PL Special Edition, p291:

void f1(T a)
{
T v[200];
T* p = &v[0];
p--; // please note (my comment)
*p = a; // oops: 'p' out of range, uncaught
++p;
*p = a; // ok
}

And here's an excerpt from p92:

"The result of taking the address of the element before the initial element
is undefined and should be avoided."

The author says, as I understand, it's ok with ++p after p--, which I think
contradict the statement in the excerpt. What do you think?


According to Google it's not in the errata list.

Executing those statements in sequence is definitely Undefined Behavior,
and in particular the increment can not "fix" the earlier invoked UB.

Mail Bjarne and get the $30 prize money (or whatever the amount is... ;-)).


Actually there is not any book error, since it is stated that undefined
behaviour is invoked.

I'm assuming the "ok" comment is from the book.

If so then this is an error.

See reply to your other response.
 
E

ES Kim

Ioannis Vranos said:
ES said:
Here's a code fragment from TC++PL Special Edition, p291:

void f1(T a)
{
T v[200];
T* p = &v[0];
p--; // please note (my comment)
*p = a; // oops: 'p' out of range, uncaught
++p;
*p = a; // ok
}

And here's an excerpt from p92:

"The result of taking the address of the element before the initial element
is undefined and should be avoided."

The author says, as I understand, it's ok with ++p after p--, which I think
contradict the statement in the excerpt. What do you think?


p--; produces undefined behaviour since it points to an invalid element.
This is allowed only for one past the end element of a sequence.

++p; reincrements the pointer and points to the first element. In this
place, p is again pointing to a valid element and in this state it is
well defined.

There's no guarantee that "p is again pointing to a valid element".
Even one UB will make every following well-defined statements undefined.
 
E

E. Robert Tisdale

Alf said:
That is incorrect.

The result of the decrement is UB.

The result of incrementing that result is UB, not a "reincrement".

Evidently, Alf is unclear on the concept of undefined behavior.

Alf,

Claiming the result of the increment is not "reincrement"
implies that the behavior *is* defined.
The standard certainly allows the implementation
to define the behavior of the increment (in this case)
to be "reincrement" and every standard compliant implementation
currently in existence defines it this way.
 
D

David Hilsee

E. Robert Tisdale said:
Evidently, Alf is unclear on the concept of undefined behavior.

Alf,

Claiming the result of the increment is not "reincrement"
implies that the behavior *is* defined.
The standard certainly allows the implementation
to define the behavior of the increment (in this case)
to be "reincrement" and every standard compliant implementation
currently in existence defines it this way.

Given the context, I think Alf's comment is correct. While UB really means
that anything can happen, including "reincrement", the original assertion,
from my understanding, was that the behavior was always defined to be
"reincrement" and only "reincrement", which is not strictly true. But, as
Bill Clinton would say, that all depends upon what we mean by "is". ;-)

You're right, though, it could always work on a given implementation, and it
does work on most implementations (or virtually all implementations, as you
have maintained in the past). In the eyes of the standard, however, it's
just UB.
 
I

Ioannis Vranos

David said:
Given the context, I think Alf's comment is correct. While UB really means
that anything can happen, including "reincrement", the original assertion,
from my understanding, was that the behavior was always defined to be
"reincrement" and only "reincrement", which is not strictly true. But, as
Bill Clinton would say, that all depends upon what we mean by "is". ;-)

You're right, though, it could always work on a given implementation, and it
does work on most implementations (or virtually all implementations, as you
have maintained in the past). In the eyes of the standard, however, it's
just UB.


Pointing to an invalid element, is undefined behaviour.


In reality, when the pointer gets reincremented, it does point to a
valid element and not somewhere else.


However "legally" speaking, the undefined behaviour invoked can even
change the value of the pointer itself and in such a case reincrementing
it will not point to the same object.


In general, when UB is invoked, the rest of the code is UB too.


So I have to agree with Alf in the end. :)
 
I

Ioannis Vranos

ES said:
There's no guarantee that "p is again pointing to a valid element".
Even one UB will make every following well-defined statements undefined.


Yes, you are right.
 
J

JKop

ES Kim posted:
Here's a code fragment from TC++PL Special Edition, p291:

void f1(T a)
{
T v[200];
T* p = &v[0];
p--; // please note (my comment)
*p = a; // oops: 'p' out of range, uncaught
++p;
*p = a; // ok
}

And here's an excerpt from p92:

"The result of taking the address of the element before the initial
element is undefined and should be avoided."

The author says, as I understand, it's ok with ++p after p--, which I
think contradict the statement in the excerpt. What do you think?

Well consider this:

If you use reinterpret_cast to convert a pointer value to an unsigned
integral value (assuming the integral type is large enough to hold the
value) and then reconvert it back, then you're left with a valid pointer.

So while the following may be invalid:

int jack[6];

int* p = jack;

--p; //There may be overflow, for instance if p == 0


I'd advocate that the following *is* legal:


int jack[6];

int* p = jack;

unsigned long address = reinterpret_cast<unsigned long const>(p);

--address;
//We don't have to check for overflow because it's
//guaranteed not to occur with unsigned integrals.

p = reinterpret_cast<int* const>(address);

//Now 'p' points to one before the start of the array.

++address;

p = reinterpret_cast<int* const>(address);

//And now we're back to the first element



In short, I would say that it's safe to increment or decrement a pointer
however you see fit, but just watch out for overflow! For instance:

int blah[50];

int* p = blah;

--p; //You can't be sure there's no overflow!


To simply say "it's UB to do this" even though there's a perfect logic
behind it to illustrate what's going on, is simply being formal and
pedantic.


-JKop
 
S

Steven T. Hatton

Alf P. Steinbach wrote:

According to Google it's not in the errata list.

Executing those statements in sequence is definitely Undefined Behavior,
and in particular the increment can not "fix" the earlier invoked UB.

Mail Bjarne and get the $30 prize money (or whatever the amount is...
;-)).
There are several examples like this. It would be a mistake to read the
textbook examples containing such UB as collectively well defined. They
are merely pedagogical devices containing inconsistencies for the sake of
brevity.

--
"If our hypothesis is about anything and not about some one or more
particular things, then our deductions constitute mathematics. Thus
mathematics may be defined as the subject in which we never know what we
are talking about, nor whether what we are saying is true." - Bertrand
Russell
 
I

Ioannis Vranos

JKop said:
Well consider this:

If you use reinterpret_cast to convert a pointer value to an unsigned
integral value (assuming the integral type is large enough to hold the
value) and then reconvert it back, then you're left with a valid pointer.


Where did you read that?


From the C90 draft that I have:

"Conversions that involve pointers (other than as permitted by the
constraints of $3.3.16.1) shall be specified by means of an explicit
cast; they have implementation-defined aspects: A pointer may be
converted to an integral type. The size of integer required and the
result are implementation-defined. If the space provided is not long
enough, the behavior is undefined. An arbitrary integer may be
converted to a pointer. The result is implementation-defined."



So while the following may be invalid:

int jack[6];

int* p = jack;

--p; //There may be overflow, for instance if p == 0



The above doesn't make sense.


I'd advocate that the following *is* legal:


int jack[6];

int* p = jack;

unsigned long address = reinterpret_cast<unsigned long const>(p);

--address;
//We don't have to check for overflow because it's
//guaranteed not to occur with unsigned integrals.

p = reinterpret_cast<int* const>(address);

//Now 'p' points to one before the start of the array.

++address;

p = reinterpret_cast<int* const>(address);

//And now we're back to the first element


The above is non-sense. Consider this:


#include <iostream>

int main()
{
int array[10]={1,2,3,4,5,6,7,8,9,10};

char *p=reinterpret_cast<char *>(&array[0]);

// Reads the first byte of every int in the array
for(unsigned i=0; i<10; ++i)
std::cout<<static_cast<int>(p[i*sizeof(*array)]);
}




Or in other words p[5*sizeof(int)] refers to the 5th element of the int
array as opposed to p[5] which would read the 5th element of a char array.
 
J

JKop

From the C90 draft that I have:

Wrong language dude.


Anyway, regarding C++:


5.2.10

5 A value of integral type or enumeration type can be explicitly converted
to a pointer.64) A pointer converted
to an integer of sufficient size (if any such exists on the implementation)
and back to the same pointer type
will have its original value; mappings between pointers and integers are
otherwise implementation-defined.


-JKop
 
R

Richard Herring

E. Robert Tisdale said:
Evidently, Alf is unclear on the concept of undefined behavior.

Alf,

Claiming the result of the increment is not "reincrement"
implies that the behavior *is* defined.
The standard certainly allows the implementation
to define the behavior of the increment (in this case)
to be "reincrement" and every standard compliant implementation
currently in existence defines it this way.

Do you have documentation for this stupendously sweeping claim?

Or are you merely suggesting that there are no standard-compliant
implementations?
 
E

ES Kim

JKop said:
If you use reinterpret_cast to convert a pointer value to an unsigned
integral value (assuming the integral type is large enough to hold the
value) and then reconvert it back, then you're left with a valid pointer.

So while the following may be invalid:

int jack[6];

int* p = jack;

--p; //There may be overflow, for instance if p == 0

That is, if p is null pointer?
Surely you're joking, Mr. JKop. ;-)
I'd advocate that the following *is* legal:

[your logic snipped]
To simply say "it's UB to do this" even though there's a perfect logic
behind it to illustrate what's going on, is simply being formal and
pedantic.

Each implementation has its own "perfect" logic. The problem is, there are
some disagreements among them, and what we call UB is a kind of the
disagreement.
I admit I've never seen any implementation that causes trouble with the
original code, but that does not mean it will be ok all the time in the future.
 

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
473,995
Messages
2,570,236
Members
46,822
Latest member
israfaceZa

Latest Threads

Top