Re: by-const-ref vs. by-value
typedef std::vector<T>::iterator Iter;
transform( Iter beg, Iter end, T const& val )
{
for( ; beg != end ; ++beg ) {
*beg += val; // is every element increased by the same value?
}
}
void fun( std::vector<T> & rng )
{
Iter pivot = find_pivot_element( rng.begin(), rng.end() );
transform( rng.begin(), rng.end(), *pivot );
}
I think that you simply attributed a meaning to a pass-by-ref that is
not envisaged by the language. When function declares that it uses a
const& param, it merely makes a promise that it will not try to modify
it - no more, no less. What you attributed to it is that a const&
param means that param will not change while inside a function. I find
that a bit surprising. I always thought that const& param is a help
for the callee - it receives a thing it should not change, and
compiler makes sure that it does not try to change it.
I am not sure if I understood what you are saying, so sorry if I just
repeat your thought with my words.
Yes, as I see it now, passing argument by reference means that the
object that is referenced will not be modified via this const
reference during the function execution, but may be modified lots of
times and arbitrary moments via other references which may not be
easily visible (e.g. due to aliasing).
Interestingly, this statement it is not in conflict with const-casts;
because cast only creates another (mutable) reference; the original is
still const, and still cannot be used to modify the object.
What I find fascinating about this topic is what I thought was also
the meaning of const but really is not:
1. A const-ref param is not a guarantee to the caller that we will not
modify the object; because of (for example) aliasing.
2. It is not a guarantee to the callee that the value of referenced
object will not change during the function execution (even assuming a
single thread application); due to alising.
3. It is not a guarantee for the callee that it is not modifying the
object referenced: because it may be unconciously modifying it via an
"aliased" reference.
If you look at your transform example, transform does not modify
object referenced by val, it modifies that object through a non-const
reference. That non const reference went in through "Iter beg". "beg"
is your "alias through a global object".
Right, I was just making the point that aliasing, invalidates some
(apparently incorrect) assumptions about const-ref arguments. But I
object to calling my example "alias through a global object". It could
all be wrapped into a function and there would be no global objects
whatsoever. One could call it "alias through another reference."
The rest of my post is not in reply to yours, but to all others.
I didn't want to start a discussion of whether by-val or by-const-ref
is better, or which one should be used, as such decisions are usualy
made per particular case, rather than a generic "best practise". As
was pointed out, object managing resources, or object that we know are
likely to generate a time-or-memory consuming copy are disqualified by
passing by-val.
I just wanted to show how by-const-ref might be different to what we
think it is. I suspect, that if it was not obvious to me it may not be
obvious to someone else too. Aliasing is just one "issue". There are
still const-casts, and in multi-threaded environments, aliasing is
even more common.
Regards,
&rzej
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]