Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C++ > Constant qualifier pros/cons, type const& versus const type&, etc.

Reply
Thread Tools

Constant qualifier pros/cons, type const& versus const type&, etc.

 
 
paulo
Guest
Posts: n/a
 
      03-05-2009
Hi,
I've always been trying to search for the best coding standard.
By now I understand that every project/person has its own favorite way
of laying out their code.
Well, I'm ok with most of it, but there's one part that I think goes
beyond pure coding stile. Or maybe not...

I'm talking about the constant qualifier.
My question can be stated as "where can I read about the best
practices for the const qualifier usage"?

For example. When I learned c++ I was thought to use:
class A {};

class B {
public:
//...
B const& attributeName() const;
void attributeName(B const& b) const;
private:
B attribute_name_;
};

I do think it's a good thing to always make constant something that
shouldn't be modified.
So, whenever that situation comes about I write:
SomeType const t(some_initialization_parameter);
//don't want t to be modified from here on...

Sometimes this is actually complicated, as in for loops: (same thing
for iterators)
for(vector<int>::size_type i(0), end(_vector.size()); i != end; ++i)
//here I could modify both i and end. Not good!

I would like to be able to write
for(vector<int>::size_type i(0), const end(_vector.size()); i != end; +
+i)
//sometimes it would be good to write here
vector<int>::size_type const i' = i;

Well, if I declare/initialize "end" before the loop this problem will
disappear, but
I'll pollute the scope with that name.
As for the i', there's no way to guarantee that i would not be
modified anyway.
Any good/elegant idea on how to do this?

Actually I'm just being a bit psychotic, trying to make the compiler
spot all my possible missuses of the language.


Another thing is the point that I fighting with right now.
Consider the following code:

void procedure(A const& a);

is this preferable to, for example:

void procedure(const A &a) const;

And why?


What about the pointer (or basic type) case. Allot o people will
write:

void someProcedure(const B* pb);

Completely different from:

void someProcedure(B const *const pb);

or

void someProcedure(const B* const pb);

Which is not as pretty but is arguably safer.

I would just like to hear/read some opinions about this subject.
I think it might not be considered very important, apart from this
last example, but if some one cares about it, please I would like to
know your opinion.

Thank you.
 
Reply With Quote
 
 
 
 
abhay.burli@gmail.com
Guest
Posts: n/a
 
      03-05-2009
On Mar 5, 7:14*am, paulo <(E-Mail Removed)> wrote:
> Hi,
> I've always been trying to search for the best coding standard.
> By now I understand that every project/person has its own favorite way
> of laying out their code.
> Well, I'm ok with most of it, but there's one part that I think goes
> beyond pure coding stile. Or maybe not...
>
> I'm talking about the constant qualifier.
> My question can be stated as "where can I read about the best
> practices for the const qualifier usage"?
> [...]
> Thank you.


Abt placement of const qualifier in code, read what the language
inventor has to say @ http://www.research.att.com/~bs/bs_f...constplacement

IMHO, it is safer to place const after the type, to avoid typedef
pitfalls.
Ex: typedef char * pchar;
now you declare mystrcmp(const pchar, const pchar);
this actually is mystrcmp(char * const , char * const); instead of the
intended const char * in mystrcmp parameters.

 
Reply With Quote
 
 
 
 
Juha Nieminen
Guest
Posts: n/a
 
      03-05-2009
http://www.velocityreviews.com/forums/(E-Mail Removed) wrote:
> IMHO, it is safer to place const after the type, to avoid typedef
> pitfalls.
> Ex: typedef char * pchar;
> now you declare mystrcmp(const pchar, const pchar);
> this actually is mystrcmp(char * const , char * const); instead of the
> intended const char * in mystrcmp parameters.


Exactly how does "const after the type" solve the problem? If you
write: mystrcmp(pchar const, pchar const), its meaning is identical to
the above.
 
Reply With Quote
 
Juha Nieminen
Guest
Posts: n/a
 
      03-05-2009
paulo wrote:
> I do think it's a good thing to always make constant something that
> shouldn't be modified.


I have self-learned the same habit.

> Sometimes this is actually complicated, as in for loops: (same thing
> for iterators)
> for(vector<int>::size_type i(0), end(_vector.size()); i != end; ++i)
> //here I could modify both i and end. Not good!


Well, there are things which the language syntax just doesn't support,
so you'll just have to live with them.

You could put the loop body into its own function and pass the loop
index as a const parameter, but that's often more trouble than it's
worth (especially if the loop body needs access to variables in the same
scope as the loop itself).
 
Reply With Quote
 
James Kanze
Guest
Posts: n/a
 
      03-05-2009
On Mar 5, 9:55 am, Juha Nieminen <(E-Mail Removed)> wrote:
> (E-Mail Removed) wrote:
> > IMHO, it is safer to place const after the type, to avoid
> > typedef pitfalls.
> > Ex: typedef char * pchar;
> > now you declare mystrcmp(const pchar, const pchar); this
> > actually is mystrcmp(char * const , char * const); instead
> > of the intended const char * in mystrcmp parameters.


> Exactly how does "const after the type" solve the problem? If
> you write: mystrcmp(pchar const, pchar const), its meaning is
> identical to the above.


The problem is that people tend to read the typedef'ed
declaration as if it were a macro, interpreting "const pchar" as
"const char*", and "pchar const" as "char * const".

More generally, there are cases where the const must come after
what it modifies, and there are cases where it can go either
before or after. Since you have to put it after in some cases,
coherence argues for doing so everywhere.

More generally: in the declaration specifier part of a
declaration, order plays no role: you can write things like
int const long static unsigned i ;
and it's legal. I'd argue that a good coding standard will
define an order. Two more or less "invariants" I've seen are:

-- The storage specifier (static, extern, etc.) is always
first. (I think C99 even deprecates putting it elsewere.)

-- Direct type modifiers (like long or unsigned) always precede
the base type, if the base type is present, and the
signedness modifier precedes the size modifier. In other
words: "long int" instead of "int long", and "unsigned char"
instead of "char unsigned". Also, no other elements are
interposed---I've never seen anything like "long const int",
for example.

The rule for const in this context varies: on one hand, it's
also a "type modifier" of sorts, so should come in front; on the
other, it must come after in contexts outside of the declaration
specifier, so consistency says put it after here as well. I
personally prefer after, but I'll go along with the local coding
conventions---it's one of those things that really aren't worth
arguing about.

--
James Kanze (GABI Software) email:(E-Mail Removed)
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
 
Reply With Quote
 
abhay.burli@gmail.com
Guest
Posts: n/a
 
      03-05-2009
Juha ..@ .. wrote
>> Exactly how does "const after the type" solve the problem? If you
>>write: mystrcmp(pchar const, pchar const), its meaning is identical to
>>the above.


Actually, i wanted to tell that const binds to the right of the
type in some situations like this, so it will help if one is in the
habit
of using it after the type.

Another reason is as explained by Josuttis in his book: C++ Templates:
The Complete Guide

It make two points, in support of using const after a type, rather
than before it (that is int const, rather than const int):

This way, what is constant is always in front of the const qualifier
(such as int const and int * const) so that textually substituting a
typedef with its type gives the same type

Ex.
The last two lines mean same here ...

typedef int * PINT;
typedef PINT const CPINT;
typedef int * const CPINT;


Whereas in the following, it means something different:

typedef int * PINT;
typedef const PINT CPINT;
typedef const int * PCINT;

Yes, there is no point in debating this. As JK said this issue is
subjective and is more of a matter of one's taste. Better to follow
the local coding guidelines.

Regards,
Abhay
 
Reply With Quote
 
Juha Nieminen
Guest
Posts: n/a
 
      03-05-2009
James Kanze wrote:
> -- The storage specifier (static, extern, etc.) is always
> first. (I think C99 even deprecates putting it elsewere.)
>
> -- Direct type modifiers (like long or unsigned) always precede
> the base type, if the base type is present, and the
> signedness modifier precedes the size modifier. In other
> words: "long int" instead of "int long", and "unsigned char"
> instead of "char unsigned". Also, no other elements are
> interposed---I've never seen anything like "long const int",
> for example.


What about things like volatile and mutable?
 
Reply With Quote
 
Bo Persson
Guest
Posts: n/a
 
      03-05-2009
(E-Mail Removed) wrote:
> Juha ..@ .. wrote
>>> Exactly how does "const after the type" solve the problem? If you
>>> write: mystrcmp(pchar const, pchar const), its meaning is
>>> identical to the above.

>
> Actually, i wanted to tell that const binds to the right of the
> type in some situations like this, so it will help if one is in the
> habit
> of using it after the type.
>
>
> This way, what is constant is always in front of the const qualifier
> (such as int const and int * const) so that textually substituting a
> typedef with its type gives the same type
>
> Ex.
> The last two lines mean same here ...
>
> typedef int * PINT;
> typedef PINT const CPINT;
> typedef int * const CPINT;


Some of us, who actually happen to like const at the front, would
never ever do CPINT and PCINT typedefs anyway. They are extremely
ugly!

So there is no problem!

>
> Yes, there is no point in debating this. As JK said this issue is
> subjective and is more of a matter of one's taste. Better to follow
> the local coding guidelines.


Right!


Bo Persson


 
Reply With Quote
 
James Kanze
Guest
Posts: n/a
 
      03-06-2009
On Mar 5, 7:02 pm, "Bo Persson" <(E-Mail Removed)> wrote:
> (E-Mail Removed) wrote:


[...]
> > The last two lines mean same here ...


> > typedef int * PINT;
> > typedef PINT const CPINT;
> > typedef int * const CPINT;


> Some of us, who actually happen to like const at the front,
> would never ever do CPINT and PCINT typedefs anyway. They are
> extremely ugly!


Some of us who prefer the const at the back would never use such
typedef's either.

There are more complicated cases, where a typedef might be
appropriate. But globally, IMHO, the typedef argument is an
argument, but a weak one---the declaration syntax and semantics
of C++ are complicated enough that any C++ programmer will have
to learn them anyway, and they involve a lot more than just
reading off the elements in order.

--
James Kanze (GABI Software) email:(E-Mail Removed)
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
 
Reply With Quote
 
James Kanze
Guest
Posts: n/a
 
      03-06-2009
On Mar 5, 12:54 pm, Juha Nieminen <(E-Mail Removed)> wrote:
> James Kanze wrote:
> > -- The storage specifier (static, extern, etc.) is always
> > first. (I think C99 even deprecates putting it elsewere.)


> > -- Direct type modifiers (like long or unsigned) always precede
> > the base type, if the base type is present, and the
> > signedness modifier precedes the size modifier. In other
> > words: "long int" instead of "int long", and "unsigned char"
> > instead of "char unsigned". Also, no other elements are
> > interposed---I've never seen anything like "long const int",
> > for example.


> What about things like volatile and mutable?


Don't use them. Seriously, volatile is a cv-qualifier, and
everywhere I've seen it used, it has followed the rules of
const. Mutable is a bit special (in my mind, at least); I tend
to think of it almost like a storage class, and put it at the
start, but arguably, it is closer to a cv-qualifier. (The big
difference, of course, is that it can only be used in the
declaration specifier, to apply to the declared object---you
don't have e.g. mutable qualified lvalues, or pointers to
mutable.)

And of course, none of these would ever be put between int and
long, or long and unsigned. (At least, I've never seen anyone
who would do that in real code.) But something like "int
mutable long" is perfectly legal.

--
James Kanze (GABI Software) email:(E-Mail Removed)
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
type compatible and const qualifier nicolas.sitbon@gmail.com C Programming 12 12-14-2008 07:39 AM
Re: Mozilla versus IE versus Opera versus Safari Peter Potamus the Purple Hippo Firefox 0 05-08-2008 12:56 PM
const type qualifier and external linkage (term.?) Ben Petering C Programming 7 12-31-2007 05:01 AM
const type qualifier after function name minseokoh@hanafos.com C++ 9 09-09-2007 07:26 PM
const vector<A> vs vector<const A> vs const vector<const A> Javier C++ 2 09-04-2007 08:46 PM



Advertisments