On Thu, 18 Nov 2004 14:45:01 +0000, S.Tobias wrote:
....
> I'm thinking of having a pool of transparent struct type objects, which
> could be reused. I forbid (well... at least make it harder) the client
> to modify certain fields (`id') by designating them `const'. But in
> order to reuse the object (to avoid free()/malloc()) the object itself
> must be non-const, so that the library can regenerate `id' when another
> object is requested.
>
> (My aim would be achieved by making an opaque type and supplying
> accessor functions (C++ way), but simplicity has its merits too and I
> want to find out if "const" scheme would work.)
Structly, no, but it would take a very unreasonable implementation to
break this, even the standard suggests that in footnotes.
IMHO this is the sort of thing you document the assumption and just go
ahead. Like assuming that EOF is distinct from the values returned by
getc() for all valid characters (although nobody I know of documents
that).
>> > 1. If I have a struct type which contains a const member:
>> > struct mystruct
>> > {
>> > const int id;
>> > int mutable;
>> > };
>> > does a definition
>> > struct mystruct ms;
>> > define an object `ms' which is *partly* const?
>
>> There are 2 concepts to consider here, one is whether it is const i.e.
>> whether its type is const qualified. ms does not have a const qualified
>> type. The other is whether ms is "modifiable". A const object is
>> non-modifiable and because id has a non-modifiable member it is
>> non-modifiable as a whole, which means that things like
>
> Thanks for brining my attention to it.
>
> A small nit-pick: you talk of "non-modifiable object". As I understand
> it, objects may be const, but lvalues (expressions designating an
> object) may be modifiable; eg. we may (try to) modify const object
> through a modifiable lvalue (UB), or try to modyfy non-const object
> through non-modifiable lvalue (constraint violation). Constness belongs
> to objects and types, modifiability belongs to type system. Please
> correct me if I'm wrong.
You are correct that modifiable lvalue is a specific term defined by the
standard. I quoted my use of modifiable in eference to objects as it is my
own. It is reasonable to think of const defined objects and strin literal
objects as non-modifiable, the standard just says you get undefined
behaviour if you try to modify them.
const is just a type, i.e. compile time, concept. At runtime the issue is
whether something bad could happen if you try to write to an object, which
isn't the same as constness, although constness in the source code will
allow such badness.
>> ms = another_mystruct;
>
>> result in undefined behaviour.
>
> Or in diagnostics?
Yes, you are correct - this requires a diagnostic. The LHS of an
assignment must be a modifiable lvalue and that can't be a structure type
with any (recursively) const members.
>> > Ie. the object `ms'
>> > is not const as a whole, but modifying ms.id yields UB in all
>> > contexts?
>
>> Yes modifying ms and ms.id result in UB where the latter is not a
>> direct constraint violation.
>
> Could you please tell me how to derive it from the Standard; I think
> it's not quite obvious. (I do believe you, it's just that I'm curious
> and I want to learn.)
Since I was wrong that's tricky.

For the diagnostic you have the
constraint of C99 6.5.16 and the definition of modifiable lvalue
6.3.2.1p1. FOr UB in other const cases the reference is C99 6.7.3p5.
> I think in my previous post I might have made an error in my thinking.
> The buffer obtained from malloc() is not a const-object and I probably
> don't need mystruct_without_const at all.
Makes sense.
> Please, have a look at my new code:
>
> struct mystruct *new_mystruct(void)
> {
> struct mystruct *msp;
> msp = malloc(sizeof *msp);
> if (msp)
> {
> *(int*)& msp->id = /*generate id*/; /*well defined?*/
Looks good to me.
> msp->mutable = /*...*/;
> }
> return msp;
> }
> }
> Is that whole cast operation (simply meant to be in C++ speak:
> const_cast<int&>) correct?
>
> What effective type will the allocated buffer have after return?
AFAICS the caller code could modify the id member with
appropriate casting as you have done above and not onvoke UB. I can't see
that as a problem though. I think that's a that's significant here in
terms of "effective type".