Topic: properties of scalar objects w/ indeterminate value //iterator defect or feature?
Author: markus.mauhart@nospamm.chello.at ("Markus Mauhart")
Date: Wed, 11 Dec 2002 03:55:40 +0000 (UTC) Raw View
"James Kuyper Jr." <kuyper@wizard.net> wrote ...
>
> Markus Mauhart wrote:
>
> > BTW, from C99 I couldnt find out how conversion (-> copy, assignment)
> > between compound type objects is done: recursive copying of members
> > (like c++) or "memcopy(dst,src,sizeof(both))" ?
>
> It took me a long time to find the relevant clause; it's not in any
> location I'd have expected it to be in.
>
> C99 6.2.6.1: "When a value is stored in an object of structure or union
> type, ... the bytes of the object representation that correspond to any
> padding bytes take unspecified values. 42)"
>
> Footnote 42: "Thus, for example, structure assignment may be implemented
> element-at-a-time or via memcpy."
Thanks !
Markus.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: ark@research.att.com (Andrew Koenig)
Date: Thu, 5 Dec 2002 23:48:54 +0000 (UTC) Raw View
> AFAICS there are significant differences between iterators
> with required def-ctor and 'un-initialized' raw pointers:
> iterator i, j ;//both may be 'singular'
Correct.
> i == i ;//undefined behaviour. (OK for pointers ?)
No, it's undefined for pointers also.
> j = i ;//undefined behaviour. OK for pointers
No; copying an uninitialized pointer has undefined behavior.
> j == i ;//undefined behaviour. (OK for pointers ?)
No, it's undefined for pointers also.
> iterator k = iterator() ;//undefined behaviour. OK for pointers
Yes: If T is a pointer type, T() is equivalent to T(0).
> iterator l(i) ;//undefined behaviour. OK for pointers
No, it's undefined for pointers also.
> AFAICS this kind of well defined "copy/assignment between same types"
> applies to all 'un-initialized' ('indeterminate value') scalar types.
No -- it applies *only* to unsigned char. For all other scalar types,
the effect of trying to copy an uninitialized value is undefined.
> What is not clear for me is whether one may compare such things
> to certain other things. Naively one might guess that all such
> copies of an indeterminate value must compare equal and not !=,
> especially not raising an exception or formatting the disk !
> That leds me to the question what generally is allowed
> for scalar type objects with indeterminate values:
> typedef int*_or_double S;
> S s ;//non-static -> indeterminate value.
Yes.
> s == s ;//true or indeterminate result or undefined behaviour ?
Undefined behavior.
> S t = s;//8.5,par14: the initial value of the object being initialized
> //is the (possibly converted) value of the initializer expression.
> // => not undefined behaviour; "same value".
Undefined behavior.
> t == s ;//true or indeterminate result or undefined behaviour ?
Undefined behavior.
> t = s ;// => not undefined behaviour; "same value".
Undefined behavior.
> t == s ;//true or indeterminate result or undefined behaviour ?
Undefined behavior.
> Especially w.r.t pointers I'm not sure about comparing:
> [expr.eq] 5.10,par1: Two pointers of the same type compare equal if
> and only if they are both null, both point to the same object or
> function, or both point one past the end of the same array.
If the pointers are uninitialized, none of these conditions is true.
--
Andrew Koenig, ark@research.att.com, http://www.research.att.com/info/ark
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: jpotter@falcon.lhup.edu (John Potter)
Date: Thu, 5 Dec 2002 23:51:54 +0000 (UTC) Raw View
On Thu, 5 Dec 2002 19:23:08 +0000 (UTC),
markus.mauhart@nospamm.chello.at ("Markus Mauhart") wrote:
> "John Potter" <jpotter@falcon.lhup.edu> wrote ...
> >
> > You should never do anything other than assign a new value with a
> > default constructed iterator. It is just like int* p;
>
> AFAICS there are significant differences between iterators
> with required def-ctor and 'un-initialized' raw pointers:
The answer is quite simple. 4.1/1 An lvalue to rvalue conversion on
an uninitialized object is undefined behavior.
Thow shalt not look at an uninitialized object.
Default constructed iterators are allowed to have uninitialized
members.
typedef int* IntStar;
typedef list<int>::iterator Iter;
void f () {
IntStar p; // uninitialized
Iter it; // default constructed yet uninitialized
IntStar(); // null pointer
Iter(); // default constructed yet uninitialized
}
The last one is the surprise.
John
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: markus.mauhart@nospamm.chello.at ("Markus Mauhart")
Date: Fri, 6 Dec 2002 17:14:08 +0000 (UTC) Raw View
"Andrew Koenig" <ark@research.att.com> wrote ...
>
> > AFAICS this kind of well defined "copy/assignment between same types"
> > applies to all 'un-initialized' ('indeterminate value') scalar types.
>
> No -- it applies *only* to unsigned char. For all other scalar types,
> the effect of trying to copy an uninitialized value is undefined.
"James Kuyper Jr." <kuyper@wizard.net> wrote ...
>
> None of the above expressions work for pointers. See section 4.1: "If
> .... the object is uninitialized, a program which requires this [lvalue
> to rvalue] conversion has undefined behavior". Copy assignment between
> same types requires lvalue to rvalue conversion for the copied object;
> if that object is uninitialized, it has undefined behavior.
"John Potter" <jpotter@falcon.lhup.edu> wrote ...
>
> The answer is quite simple. 4.1/1 An lvalue to rvalue conversion on
> an uninitialized object is undefined behavior.
>
> Thow shalt not look at an uninitialized object.
Thanks for pointing this out, it was a consistent vote !
I'm only surprised about what "uninitialized" means, that is now
I have to change my mind about it.
Especially from [dcl.init] 8.5 I thought that the declarations I had
used generate initialized objects having indeterminate value, and that
only strange code can generate references to "uninitialized" objects.
[dcl.init] 8.5,par1:
A declarator can specify an initial value for the identifier
being declared. The identifier designates an object or reference
being initialized.
Therefore I thought that the following generates objects that
have been "being initialized".
iterator i;
T* p;
double d;
[dcl.init] 8.5,par9:
If no initializer is specified for an object [...] the object and
its subobjects, if any, have an indeterminate initial value90);
if the object or any of its subobjects are of const-qualified type,
the program is ill-formed.
(The last phrase actually indicates that such 'pseudo-initialized'
objects are no 1st-class citizens)
But now it looks like that in my mind I should replace ...
"have an indeterminate initial value"
with ...
"have an indeterminate initial value and are considered 'uninitialized'"
"[Note: you can not even copy or equ-compare their value]"
And probably the same then is true for C99, e.g. copying a pointer p
'initialized' only via "T* p;" is undefined behaviour, right ?
For me this is currently surprising, e.g. it tells me to be very
carfully when relying on the compiler-generated implicit def-ctor
and cpoy-ctor of a POD type:
struct basic_string<wchar_t>
{
private: wchar_t buf[32];
public: def-ctor() {buf[0] = 0;} //oops, have forgotten initializer "buf()"
cpy-ctor(y):buf(y.buf) {} //oops, reading many uninitialized wchar_t
};
Or ..
struct efficient_vector<T>
{
private: T buf[32] ;size_t len;
public: def-ctor():len() {} //oops, have forgotten initializer "buf()"
cpy-ctor(y):buf(y.buf) {} //oops, reading many uninitialized T
};
Kind regards,
Markus Mauhart.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: markus.mauhart@nospamm.chello.at ("Markus Mauhart")
Date: Mon, 9 Dec 2002 18:41:18 +0000 (UTC) Raw View
"James Kuyper Jr." <kuyper@wizard.net> wrote ...
>
> Yes. In fact, C99 is far clearer about this. C99 adds the concept of
> trap representations. For any type that can have trap representations,
> an uninitialized object of that type might contain a trap
> representation. The effect of this is pretty much the same as the rules
> for the use of uninitialized objects in C++. However, C99 makes it clear
> which types are allowed to have trap representations; it's perfectly
> safe to read, copy, and compare uninitialized objects of the types that
> can't have trap representations. All signed integer types, pointer
> types, and floating point types are allowed to have trap
> representations. So are all of the unsigned integer types except
> unsigned char and the new exact-width typedefs such as uint32_t.
Very interesting ! Originally I thought of that C that is/was relevant
for c++98, but C99 probably has more details on complicated issues.
I'm just trying to summerize:
c++98: [sub-]objects initialized with 'indeterminate' value are
considered 'uninitialized', especially they can contain 'invalid'
values, and 'initialized' objects can contain 'uninitialized'
subobjects.
All we can do with them:
Assign valid values to them, call their pseudo-destructor.
They may be source and/or dest of memcopy or any byte-access ?
(probably C9x should give the answer)
C99 has specs that c++98 is missing:
C99.3.17.2 indeterminate value
either an unspecified value or a trap representation
C99.3.17.3 unspecified value
valid value of the relevant type where this International Standard
imposes no requirements on which value is chosen in any instance
NOTE An unspecified value cannot be a trap representation.
-> 'indeterminate' value can be 'invalid' = 'trap'
(and probably c++0x should get a corresponding update)
AFAICS [C99.conversions] has no restrictions for them, instead
[C99.Representations of types] contains the only restrictions:
"If the stored value of an object has such a representation and is
read by an lvalue expression that does not have character type,
the behavior is undefined.
If such a representation is produced by a side effect that modifies
all or any part of the object by an lvalue expression that does not
have character type, the behavior is undefined.41)"
"41) Thus, an automatic variable can be initialized to a trap
representation without causing undefined behavior, but the value of
the variable cannot be used until a proper value is stored in it."
Especially 41) tells us we can assign valid values to them.
Otherwise AFAICS the bytes of such objects can be source and
destination of memcopy or any other byte-access (?)
BTW, from C99 I couldnt find out how conversion (-> copy, assignment)
between compound type objects is done: recursive copying of members
(like c++) or "memcopy(dst,src,sizeof(both))" ?
Especially the code of 'old' C[++] programmers using memcopy
to assign/copy between POD structs is save, while the modern
style of relying on the compiler generated copy for assignment/copy
of POD structs is unsave.
Kind regards,
Markus.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: markus.mauhart@nospamm.chello.at ("Markus Mauhart")
Date: Thu, 5 Dec 2002 19:23:08 +0000 (UTC) Raw View
"John Potter" <jpotter@falcon.lhup.edu> wrote ...
>
> You should never do anything other than assign a new value with a
> default constructed iterator. It is just like int* p;
AFAICS there are significant differences between iterators
with required def-ctor and 'un-initialized' raw pointers:
iterator i, j ;//both may be 'singular'
i == i ;//undefined behaviour. (OK for pointers ?)
j = i ;//undefined behaviour. OK for pointers
j == i ;//undefined behaviour. (OK for pointers ?)
iterator k = iterator() ;//undefined behaviour. OK for pointers
iterator l(i) ;//undefined behaviour. OK for pointers
AFAICS this kind of well defined "copy/assignment between same types"
applies to all 'un-initialized' ('indeterminate value') scalar types.
What is not clear for me is whether one may compare such things
to certain other things. Naively one might guess that all such
copies of an indeterminate value must compare equal and not !=,
especially not raising an exception or formatting the disk !
That leds me to the question what generally is allowed
for scalar type objects with indeterminate values:
typedef int*_or_double S;
S s ;//non-static -> indeterminate value.
s == s ;//true or indeterminate result or undefined behaviour ?
S t = s;//8.5,par14: the initial value of the object being initialized
//is the (possibly converted) value of the initializer expression.
// => not undefined behaviour; "same value".
t == s ;//true or indeterminate result or undefined behaviour ?
t = s ;// => not undefined behaviour; "same value".
t == s ;//true or indeterminate result or undefined behaviour ?
Especially w.r.t pointers I'm not sure about comparing:
[expr.eq] 5.10,par1: Two pointers of the same type compare equal if
and only if they are both null, both point to the same object or
function, or both point one past the end of the same array.
Kind regards,
Markus.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]