Boost logo

Boost Users :

From: David Abrahams (dave_at_[hidden])
Date: 2004-12-06 08:24:02


Tobias Schwinger wrote:
> David Abrahams wrote:
>
>> Tobias Schwinger wrote:
>>
>>> I see - thanks for your detailed reply.
>>>
>>> When using proxy classes as references the assumption that
>>> modifications of a temporary object are lost at the end of this very
>>> object's lifetime does not apply
>>
>>
>>
>> It most certainly does apply. There may be some cases in which it
>> doesn't, but the usual case is that it does.
>>
>
> Writing "proxy class with reference semantics" would have been more
> precise, I figure.

I guess not, really. "Reference semantics" is pretty loosely-defined,
and it's sort of the job of any proxy reference to have some kind of
"reference semantics." Could you explain some more?

>>> - modification of the proxy object actually means changing the stored
>>> data internally referenced by it.
>>
>> Normally the reason for a proxy is that there isn't any "stored data
>> internally referenced by it." If there's a persistent lvalue, why not
>> just return a real reference instead of a proxy?
>
> Because I have to change its interface.
> In my particular case the persistent lvalue is of array type.

But why not just change the interface in your dereference function and
hand back a real reference at that point? If you are not storing a copy
of the value_type within the proxy, I don't see what the proxy can be
buying you.

>> Just hand-code your own operator->.
>
> OK - that's what I did, for now.
>
>>> And why does operator* give me a mutable (temporary) object then, by
>>> the way ?
>>
>> It is assumed that if you passed non-const R for the reference type,
>> you are trying to make a writable iterator, and R will have a (usually
>> non-const) assignment operator that takes a value_type argument. If
>> we returned a const object, it would be impossible to write
>>
>> *p = x;
>>
>
> If the expression
>
> *p
>
> gives me a temporary object with no reference (write-through) semantics
> it does not make sense to write to this temporary by writing
>
> *p = x;
>
> according to your above rationale, does it ?

That is true. But when the reference type is not the same as the
value_type, an iterator author has to go out of his way to make that
assignment compile.

> Same goes for:
>
> (*p).mutator(value);

And *way* out of his way to make this one compile, since the reference
type must now have forwarding members for each member of the value_type.

> and
>
> p->mutator(value);

So now we come to this one. This one is entirely in the hands of the
library to prevent, since the user doesn't usually determine the return
type of operator->. It seems like a bad idea to allow it silently.
The library is supplying an operator-> that stores an object of the
value_type. There are very few situations where modifications to that
object can go anywhere useful, so it makes sense to prevent them. The
library is able to make sensible default choices without fear because
the user can always reimplement any operator within his derived iterator.

> ...and I can't imagine there is a user who would seriously complain that
>
> pointer ptr ( i.operator->().operator->() );
>
> gives an invalid pointer ;-).
>
>
>
> Am I missing something ?

There was a guy who complained just last week on this very mailing list
that putting an iterator_adaptor over a T const* suddenly produced
writability in the iterator through operator-> !!
http://lists.boost.org/MailArchives/boost-users/msg08656.php

-- 
Dave Abrahams
Boost Consulting
http://www.boost-consulting.com

Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net