I am reviewing the coding guideline of an organisation and one of them
states that the name of the function members should start with an 'r'
if the function returns a non-const reference (I don't want to debate
whether returning a non-const ref is a good practice or not). Here
follows an example
class A
{
public:
int &rGetValue();
const int &GetValue() const;
...
};
Clearly, without the 'r', const and non const versions of GetValue
should have been considered as an overload . Prefixing the 'r' makes
obviously these member functions not real overload. Personally, I
really hate this kind of rule, but it is just a matter of taste. Could
you give me good reasons to prefer a real overload? For example, could
this kind of rule prevent the reuse of generic code, by the fact that
their names are not aligned?
Any opinion is really welcome and thank you in advance for your
contribution.
Christophe
I really hate those kind of rules as well. It's a mild form of
Hungarian notation, and I think that has had its day with modern IDEs.
Anyway...
The point of the two accessors having the same name is that you can ask
for the value without worrying about whether or not the container object
is const. You get back a reference to the value, and if the container
is const you can't fiddle with the value. For an example of this in
real use you have to go no further than the standard library. For
example, vector contains
iterator begin()
const_iterator begin() const
... which return you iterators to the beginning of the vector with the
appropriate type for whether or not the vector is const.
Andy
If you are reviewing then you are apparently asked for your opinion.
Why our opinion matters?
> Here follows an example
>
> class A
> {
> public:
> int &rGetValue();
> const int &GetValue() const;
> ...
>
> };
Clearly i do not like const int&. I always pass int there.
> Clearly, without the 'r', const and non const versions of GetValue
> should have been considered as an overload . Prefixing the 'r' makes
> obviously these member functions not real overload. Personally, I
> really hate this kind of rule, but it is just a matter of taste. Could
> you give me good reasons to prefer a real overload? For example, could
> this kind of rule prevent the reuse of generic code, by the fact that
> their names are not aligned?
Generics should assume to get non-const references from very few
places like operator=, operator* (unary) and operator[] these you can
not prefix with r anyway.
> Any opinion is really welcome and thank you in advance for your
> contribution.
My opinion is that passing non-const reference is bad practice unless
the class under question is container-like or pointer-like. With
container-like their rule is also bad since it causes a member named
'rat':
value_type const& at( size_type n ) const;
value_type& rat( size_type n );
As for pointer-like classes these usually overload the operators. For
navigating ( next(), prev(), up(), down(), left(), right() ) you pass
a pointer or pointer-like and not a reference since it is possible
that you are at edge and have to pass NULL. I am out of cases where i
need something that passes non-const reference with non-operator and
non-rat. ;)
Öö Tiib wrote:
> My opinion is that passing non-const reference is bad practice unless
> the class under question is container-like or pointer-like. With
> container-like their rule is also bad since it causes a member named
> 'rat':
Bad practice? I think it is good if the function modifies the arguments.
e.g.
template<class t>void swap(t &a, t &b) {
t &&c = std::move(a);
a = std::move(b);
b = std::move(c);
}
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (GNU/Linux)
iEYEARECAAYFAktcKwUACgkQm4klUUKw07AGTwCdGPa9qXuqqpV9vn4VMvsRQVyE
fW0AnRoPMD690Okp++3keyX7p37jf/jI
=yFK8
-----END PGP SIGNATURE-----
It would cause the user of the class to be aware of the const-ness of
the object if he wants to make changes to the reference to the member
returned by calling the non-const version. Which means:
//consider you have an object of A named a
//I would need to have:
int & ref = a.rGetValue();
Irrespective of a being const or non-const, the const member function
gets called.
It would not affect generic code, because if it is possible to achieve
the functionality with the const version, you really don't need to
have the non-const function to be called. Which means, if there is a
function like:
void f(const A& a)
{
a.GetValue();
}
a.GetValue() would be sufficient even though the input object for f()
is a const A or a non-const A. But, this is a very different naming
convention you have. May be, the intention was to be able to identify
the locations where the non-const reference to the member was being
returned without going into the debate around if returning a non-const
reference to a member is good or bad. And may be, to prevent
accidentally, getting back a non-const reference to a member and then
the user code accidentally changing it directly or indirectly, while
with the convention, any such change would happen by an explicit call
to rGetValue like members and in those case the user code is fully
aware of what its doing.
Yes, i was mistyping 'passing'. I meant member function 'returning'
non-const references. Sorry, bad English.
...is perfectly valid C++ and doesn't invoke undefined behaviour. But
it also doesn't do what you want. In your case "c" is just another
alias of object "a" refers to. It should have been
t c {std::move(a)};
As for const-overloading, I believe the upcoming C++ standard will add
"cbegin" and "cend" to all container classes so you can easily get
const_iterators from a non-const container. So, it seems it's not
*that* bad.
Cheers,
SG
> class A
> {
> public:
> int &rGetValue();
> const int &GetValue() const;
> ...
> };
That smacks of Hungarian. In the bad sense. On the other hand,
it is quite normal for a function which allows or supports
modification of internal state to have a different names, or at
least a different signature, from one which doesn't. After all,
they're doing different things. Thus, one would expect:
int GetValue() const;
void PutValue(int newValue);
or
int value() const;
void value(int newValue);
(To give the two most frequent conventions.)
About the only case I can think of where a const and a non-const
function should be overloaded is for operator overloading.
> Clearly, without the 'r', const and non const versions of GetValue
> should have been considered as an overload.
Which is something you definitely want to avoid. It's the means
which are bad, not the end.
> Prefixing the 'r' makes obviously these member functions not
> real overload. Personally, I really hate this kind of rule,
> but it is just a matter of taste. Could you give me good
> reasons to prefer a real overload?
Obfuscation? The possibility to create obscure bugs?
> For example, could this kind of rule prevent the reuse of
> generic code, by the fact that their names are not aligned?
No.
--
James Kanze