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