And just to be clear, any other storage or computation (assignment,
passing or returning, addtion/subtraction within an array) on the
deconstified pointer is legal; it is only dereference, or subscripting
which includes dereference, that is UB.
I glossed over that. As I said, others mentioned what would occur if you
tried to modify a const-qualified variable through a pointer.
If the pointer is to const, it is a constraint violation and diagnosed
(in C; in C++ it is a violation whose diagnosis is not waived, same
result). If the pointer has had const cast away, it is UB.
[OT from here...]
I seriously doubt this. My impression is that C++ is *more*
strict about type-safety than C, not less.
That's a matter of debate. In addition to the C-style cast, C++ includes
four other casting operators. <snipped except>
If the [dynamic_cast] fails, a bad_cast exception is thrown.
For a reference; for a pointer it gives a null pointer.
const_cast allows you to strip the const, volatile and __unaligned
attributes. Here, a write through a cast pointer (including one that was
previously const) *might* be undefined, but it depends on the type of
object. I don't have any more information on that: Microsoft's
documentation stops there (there was no "Microsoft-specific" marking, so I
assume that it is standard C++).
It's standard, except for __unaligned as you might guess. Storing to
an object that was *defined* as const (and not mutable) is UB, as in
C: 7.1.5.1[dcl.type.cv]p4, as referenced by 5.2.11[expr.const.cast]p7,
and extended to deconstructed memory in 3.8[basic.life]p9; in C the
lifetime of an object is from allocation to deallocation, but in C++
for a nontrivial class type only from construction to destruction, so
this makes the const rule apply from allocation to deallocation.
If you create a const pointer to an object that is actually nonconst,
as can easily be done implicitly, then cast away const and store
through the result, that is well-defined and works in both C and C++.
Also, in C++ but not C a const variable of integer or enumeration type
initialized by a constant expression can be used in a constant
expression. This means that if you do illegally store to such a
variable, after/by forming a nonconst pointer to it, and the
implementation doesn't trap and actually does the store -- one
permitted option under UB -- it is rather likely that the stored value
will not be used in what appear to be subsequent fetches of it. A C
compiler may do this same optimization if it likes, under the (very)
broad aegis of UB, but it isn't encouraged the way C++ is.
I do have to admit that I forgot the "might be undefined" part (I usually
stick to C-style casts, and I've never cast away a const-qualifier anyway).
However, it's not quite so clear cut as others present it in C, nor is C++
any more type-safe than C, unless the developer chooses to make it so with
the more reliable casts.
It is in several places.
C++ does not allow implicit conversion from base to derived, which is
a feature that does not exist in C, but extends this principle to
prohibit implicit conversion of void* to any other data*, which C
allows; this is a FDiscussedFeature(?) on clc.
C++ considers enum types (and their values) distinct and does not
allow implicit conversion from an integer. C considers enums just
integers of some implementation-dependent size.
Optional arguments, and to some extent templates, allow some functions
with varying signatures to be written typesafely that would require
less-safe varargs in C, although that option still exists in C++.
C++ outlawed implicit int (and implicit function declaration) first,
but C99 has matched it. C++ has only the prototype syntax for
functions, not the less-safe K&R1 syntax still allowed in C.
C++ prohibited unvalued return for nonvoid functions first, but C99
has matched it; C++ also makes it UB immediately when falling off the
end of a nonvoid function, instead of trying to use the indeterminate
return value as in C, and this is often easier to diagnose though not
required. C++ also allows a return "value" of void type in a void
function, which is useful for templates, but not really needed in C.
C++ retains C's array/pointer duality and pointer arithmetic, which
are in practice impractical to make safe, but offers the option of
std::vector or other array-like classes and "smart" pointers, and in
particular std::string or other string classes for the area that has
proven most frequently (IMJ) troublesome in C.
But yes, the new more specific -- and more visible in source -- casts
are an important contributor to typesafety in C++.
- David.Thompson1 at worldnet.att.net