Fog Creek Software
Discussion Board




Trying to be C++ const correct!

Let's say I have this function:

BOOL CSomeClass:Foo() const
{
    return (bA_Flag && bAnother_Flag);
}

Now, I understand that I can have the const after Foo() because I don't change the state of the Object.

BUT,
what about the return value?  Can I write const BOOL here?  What's an easy way to think about this one?

Thanks!

William C
Thursday, September 11, 2003

const or no const doesnt matter here if BOOL is actually a typedef to some built in type. Ask yourself what would be the purpose of placing const there?

Passater
Thursday, September 11, 2003

You are returning the type directly, rather than indirectly (through a pointer or a reference). Const doesn't come into play on the return type.

Brad Wilson (dotnetguy.techieswithcats.com)
Thursday, September 11, 2003

You mean something like

"const BOOL CSomeClass:Foo()"?

I am not sure what this is supposed to mean to the compiler.  Perhaps something like this?

const BOOL x = bar.Foo();
// can't change x now?
const BOOL y = bar.Foo();
// can't change y, but can it be different than x?
BOOL z = bar.Foo();
// compile error?

This whole exercise strikes me as silly.  Why would anyone ever want to do that?

Alyosha`
Thursday, September 11, 2003

>>>
This whole exercise strikes me as silly.  Why would anyone ever want to do that?
>>>

Wow, Alyosha' .. sorry that I had to ruin your day and all.  I bow to your greateness.  I guess that when you were learning something, you never asked questions.  Or this is the reaction you usually got, so now you have some pavlovian response.  Sorry to hear that.

I think maybe BOOL was a bad example.  Let's say it was returning a string (CString).  I think what I was getting at was:

even though it was the flags, at the time of the call, that determine the value of the String (so the string could change once the flags change).  The caller of this function, shouldn't be changing the value of the String once it receives it.  Let this function determine the value.  And yes, although the calling function is probably using some local variable to store the result of the function call .. I don't know enforce the fact that this and only this function should be distributing the string value.  So, I don't know, maybe they were trying to store the string result in a member variable.  So, applying const CString or whatever...kind of tells them to not store the variable.

These are the thoughts that were running through my brain.  Is this NOT so silly now?

William C
Thursday, September 11, 2003

Const rules as I recall:

const return-type functioncall()

The value returned is const. I don't see this being meaningful on anything other than when returning a pointer or reference to encapsulated data (which should be done very very carefully).

There's some other places const can go, and I'll look em up and post em if you like.

I suggest you go buy Scott Meyer's Effective C++ books, and a good C++ reference. The Meyers book has a table on what const means where you can put it (and where you should put it).

Mike Swieton
Thursday, September 11, 2003

>>>
The value returned is const. I don't see this being meaningful on anything other than when returning a pointer or reference to encapsulated data (which should be done very very carefully).

There's some other places const can go, and I'll look em up and post em if you like.
>>>

Thanks Mike.  You don't have to look things up, I can do that! :)  I was just looking to get "off the top of the head" thoughts from C++ programmers regarding const.  And not even just const when dealing with the return type.  I'm sure there are people who have been developing (with C++) for 10, 20 years that have grasped this idea and can explain it in a way that others might not have heard or read.  I'm looking for stuff like that.

I'm basically trying to use C++ correctly, which is good!  Right?  Initiative and all?  Betterment and all?  :)  Because I see read other people's code all the time, and I don't think a lot of newbie or experienced programmers even bother with const.  I don't want to be that guy.

William C
Thursday, September 11, 2003

Let me add something about the const BOOL example:

Let's say you have a member variable of a class.  In this instance, it's probably static const (because it doesn't change).

I'm guessing this is the only time you would have const BOOL as the return type, then? (based on the reaction).

I just want to point out, that this could be an instance where you have const BOOL.  Maybe it's me over-thinking some examples (which is possible), but I'm always trying to tell a story (per se) to other coders when I'm coding.  So, maybe I overuse const in some instances (where it's not needed).  The purpose of it would just be to tell a programmer (just by looking at the function declaration) what I'm intending.  And if I didn't want you storing that BOOL/CString in a member variable ... well, that's why I might be putting it there with the return type.

Anyhow, now I'm babbling.  I think I'm making up for the fact that I was getting slammed for my original, simple post.  I wanted to keep it short because I didn't want to litter the post with too much text.  Like I said, just trying to get discussion brewing. :)

William C
Thursday, September 11, 2003

"Let's say you have a member variable of a class.  In this instance, it's probably static const (because it doesn't change). I'm guessing this is the only time you would have const BOOL as the return type, then? (based on the reaction)."

They get their own copy. There's no way that they're changing their copy could have any effect on you or your data integrity. So what's the point, then? You can make a copy of a const thing without discarding its constness.

Brad Wilson (dotnetguy.techieswithcats.com)
Thursday, September 11, 2003

Oops, that "they're" should be "their". :-p

Brad Wilson (dotnetguy.techieswithcats.com)
Thursday, September 11, 2003

OTTOMH, returning a const value is quite significant in C++. Presume that BOOL is a programmer-defined type. A function:

const BOOL someFunction(...) ...

means that you can only call the const member functions of the BOOL that is returned.

This is very important if you are exposing a privatge member variable (quite possibly a bad idea). For example:

const BOOL & getFoo () const ...

this says you are returninga reference to a const BOOL. Presumably it is const so that you don't accidentally modify it in some way: that would break the 'const-ness' of the getFoo member function.

Of course, one of Scott's tips is to avoid exposing private members :-)

http://www.braithwaite-lee.com/

Reginald Braithwaite-Lee
Thursday, September 11, 2003

>>>
They get their own copy. There's no way that they're changing their copy could have any effect on you or your data integrity. So what's the point, then?
>>>

Hmm, I think my point was that if I declared a const member variable in a Class.  And then I'm going to return this value .. wouldn't I add const to the return type?  This would then tell the calling function that this is a value that doesn't change.  I think that's where I was getting at.  In other words, it's more informational.

William C
Thursday, September 11, 2003

>>>
Of course, one of Scott's tips is to avoid exposing private members :-)
>>>

You know, one of the things I try to do is avoid get methods.  Which can be difficult.

For example, I have a CPropertySheet and it, of course, has some CPropertyPage's that get added.  Now, I wanted all the input controls on any of the page's to be read-only until they clicked a "start" menu item.  Once they clicked start (which set an m_bIsStartClicked private member variable -- OnFileStart is mapped in the sheet), then they can add data to input fields.

Well, the page's need to know if they are in read-only mode or not.  Thus, the need for an IsReadOnly method in the Sheet to determine if I can enable/disable the controls on the activepage.

I suppose I could get around this by having a function in the sheet that went through every page (check for NULL first, no controls unless the tab has been tapped), dynamically found all the control windows and enabled them.  I guess I found my answer there!  Hmmm, maybe I'll find another example where it's not as easy to get around it. :)  But even so, the Sheet has to use get methods...to get the pages and then get the controls.  So, I always end up "getting" something somewhere.  (Of course, someone will probably come along with some slick thing that I've never thought of before .. to avoid any get's in this situaion .. but hey, I'm trying to learn!!)

William C
Thursday, September 11, 2003

There seems to be a lot of confusion in this thread for such a simple question!
The quick answer is that it doesn't matter when the return is by value (the "const BOOL foo() const" of the original question).  The BOOL that is returned in no way references the member BOOL - it's a copy of it.  Nothing you could legally do to return value can modify the member.
In the case where the signature is something like "std::string& foo() const", the compiler will give a warning if you try to return a member variable (something like "unable to convert const std::string to std::string&"), until you change the return value to const std::string&.  This is because the caller would have a reference to the member variable, and would be able to modify the member, like in "bar.foo() = "different string" ".

Brian
Thursday, September 11, 2003

Sheesh, William, don't flip a bit.  I don't post here just to score brownie points with the regulars.  I'm trying to be helpful.

All I did was look at what returning a const might mean, and then asking myself whether I'd ever need to do that.  And after taking a step back, I realized that returning a const really is pretty useless.  That's why I called it "silly".  So even if compilers support it, there's no reason why anyone would use it.

As Reginald pointed out, there's a difference between returning a const variable and a const reference.

================
const int g_constFoo = 42;

int getFoo( )
{
.  return g_constFoo;
}

int main( )
{
.  int x = getFoo( );
.  x = 12;
.  // doesn't change g_constFoo, so getFoo( ) need not
.  // return const
}
================
const int g_constFoo = 42;

const int& getFoo ( )
{
.  return g_constFoo;
}

int main ( )
{
.  const int& x = getFoo ( );
.  x = 12;
.  // changing x changes g_constFoo, cause it's a reference
.  // so "x = 12" is a compiler error.
.
.  int y = getFoo ( );
.  y = 12;
.  // y is a copy, so it need not be const.  changing y does
.  // not change g_constFoo.
}
==============

But then again, as Reginald also pointed out, returning references to member variables is just a Bad Idea in general.

Alyosha`
Thursday, September 11, 2003

Brian,

like I mentioned before.  I was over-thinking this to allow this const information to the programmer, not the compiler.

In other words, yeah .. sure ... it's making a copy of the BOOL so the calling function can do whatever it wants without affecting the member Variable.  Sure, yes, I understand this.

Where I'm over-thinking, is in using const as something that's informational to another programmer.  For example, the const in this example:
BOOL Foo() const

tells the programmer that this function doesn't affect the state of the object.

So, I was thinking...well, if I'm going to return a const value in a get method...why not do this:
const BOOL Foo().

This would tell the programmer that the private member variable I'm accessing with my "get" method is constant.  So, it never changes.  This may/may not be helpful.  Who knows?

Of course, there's always the thought about not having get methods.  But that's not what I'm discussing here! :)  I'm talking about const.

I'm not sure why this would be so radical this thought of mine! :)

William C
Thursday, September 11, 2003

"This would tell the programmer that the private member variable I'm accessing with my "get" method is constant.  So, it never changes.  This may/may not be helpful.  Who knows?"

It's not helpful.  It's a PRIVATE member variable.  Ergo, the programmer is required to not care if the field is variable, constant, volitile, static, synchronized, upside-down or over-easy.

Making a class method const is useful for the writer of the class (so they don't unintentionally modify member fields in their implementation, caveats with pointers notwithstanding) and for the user of the class (if they have const std::string foo("Foo"), they can only call const members; they are not allowed to change the state of the the string.

Alyosha`
Thursday, September 11, 2003

I don't have time to read all of the C++ BS that followed your question, but to answer your original question:

Yes, you can put const BOOL there, and yes, there are valid reasons for doing it (as you suggest).

a real life, actually experienced c++ coder
Thursday, September 11, 2003

>>>
Sheesh, William, don't flip a bit.  I don't post here just to score brownie points with the regulars.  I'm trying to be helpful.
>>>

Yes, and I appreciate it.  I just think you (or maybe not you), but a lot of people fail to understand that tone cannot be interpreted through a message board.  I think using "silly" and "why would anyone want to do that!?" in response to someone's question (in a message board) is well, silly! :)  Didn't make me feel smart!

>>>
But then again, as Reginald also pointed out, returning references to member variables is just a Bad Idea in general
>>>

The thing is, I see "Get methods" all the time, in 99.9% of the code I read.  So yes, I understand it's bad, and I try to avoid it, but sometimes through my inexperience, I end up having no choice but to use a "Get" method.

Take the example I gave previously.  I do try to seperate logic from the view.  So, my "sheet" acts as the place where I place my logic, and my "page" acts as the view.  So, when they clicked the "Start" menu item, that set the m_bIsStartSelected private member variable in the sheet (the logic area which can determine whether the sheet/page combo is or is not now "read only").

I ran into two choices:
1) have the page "get the readOnly" info
2) have the sheet "get the pages that it has, get the controls from those pages", and enable them using it's private info.

Either way, "getting" was happening! :(  Sometimes, it's really tough to avoid a "get".

William C
Thursday, September 11, 2003

"Hmm, I think my point was that if I declared a const member variable in a Class.  And then I'm going to return this value .. wouldn't I add const to the return type?  This would then tell the calling function that this is a value that doesn't change."

Well, I think simply saying "this isn't the purpose of const" should be enough, then. It's not informational in the sense you wish (and there is nothing in C++ to indicate what you want to indicate).

Brad Wilson (dotnetguy.techieswithcats.com)
Thursday, September 11, 2003

>>
It's not helpful.  It's a PRIVATE member variable.  Ergo, the programmer is required to not care if the field is variable, constant, volitile, static, synchronized, upside-down or over-easy.
>>

I understand.  Where I think I might be quibbling is:

1) gets are bad.  yes, we all know.
2) so normally the programmer doesn't care, because he isn't exposed.
3) avoiding gets are hard.  Sometimes "gets" slip through (remember, my experience level probably isn't the same as yours)
4) if a "get" is slipping through (as in this instance) .. shouldn't they now care?

maybe I want really, really, tight, fast code.  So, I'm looking to avoid as many function calls as possible.  I see a get method to a value I need in many different places.  I see that the return type is const BOOL.  I go ahead and store it becasue I know it doesn't change, thus avoiding subsequent calls to Foo after my 1st one.

Don't confuste the const question with whether or not the function should even exist.

William C
Thursday, September 11, 2003

How about this?  Let me switch this form being a const question (although people can still muse, because I'm interested in that subject too) to an avoiding "gets" question, for just a second.

In my sheet/page example.  How would you (to anyone) avoid a "get" here.  This could be an eye opener, and helpful to not only me.  I'm sure some have some really slick ways of doing things!

William C
Thursday, September 11, 2003

Yes.  Sometimes gets are unavoidable.

However, if you want to mark something as const for optimization purposes, it's better to cache it -- this way the user doesn't have to worry about whether it is const (and should ever change to non-const, it won't break code).

inline int getFoo( )
{
    if (!m_computedFoo)
    {
      m_foo = computeFoo( );
      m_computedFoo = TRUE;
    }
    return m_foo;
}

And if m_foo is some integer like 42, just return it directly in an inline function; you won't have the overhead of a function call.

Alyosha`
Thursday, September 11, 2003

Oh, just to add to my sheet/page example.  Now that I really think about what I said, you can't do #2 (loop through all the pages and get the controls).  When I first suggested that, that was stream of conciousness.  Now, as I think about it:

1) if you don't press on a tab, the page isn't created .. thus, the controls aren't created.
2) if they clicked file->start (thus changing it to editable), and there is an input control on a tab I haven't "tapped" yet ... I can't go through and enable it.

Thus, I'm stuck with setting the "IsReadOnly" method on the sheet that the page calls (once it's been created).  This is what I mean when I say avoiding "gets" is hard! :)

William C
Thursday, September 11, 2003

I think the rule of thumb of not exposing private member data doesn't really apply in your "isReadOnly" case.  The idea is to avoid exposing references and/or pointers to the internal structures of a class, because that breaks encapsulation.  Just having getters that return *by value* some property is perfectly acceptable.  After all most classes would be pretty useless without the ability to find out something about them.

Mike McNertney
Thursday, September 11, 2003

Getting away from gets for a moment...

There is a difference between returning a const and non-const programmer-defined type by value. IOW,

const IFoo blitz(...) ...

is very different from

IFoo blitz(...) ...

Again, the first function returns a const value, the second a non-const value. Why would you do that?

I suggest it is the normal case! Say you have a function that returns the value of a cookie:

??? ICookieValue getCookieValue(const std::string &) const ...

Should the returned value ever be directly modified? I suggest not, unless a side effect of the modification is to write  the cookie back to the user's browser. So if I write:

ICookieValue getCookieValue(const std::string &) const ...

I am implying that you *should* modify the resulting value and I expect you to do that. The non-constness of the value I return is part of my interface. And if I write:

const ICookieValue getCookieValue(const std::string &) const ...

I am saying that I am giving you what I believe is a read-only object, because I have no further interest in it. If you want to write out a new value, you can do so on your own time, perhaps with a copy constructor.

This type of thinking certainly isn't mandatory, but the fact that you are returning something by value doesn't mean that const cannot have any significance.

jm20c...

Reginald Braithwaite-Lee
Thursday, September 11, 2003

I'm surprised that no one has provided a better answer to the original question.

Consider the following class (and forgive any typos or other blunders):

#include <string>

class obj
{
    public :

        explicit obj( const string & s ) : str_( s );

        string get_string() const { return str_; }
        const string get_const_str() const { return str_; }

    private :

        string str_;
};

An instance of obj is just a wrapper for a string.  There are two get methods, each of which returns a copy of the internal string by value.  They are functionally identical except that one returns a const string and the other returns a non-const string.

Now consider the following snippet:

obj a( "Hello" );
string b;
b = a.get_str();
b = a.get_const_str();

The assignment statements in the last two lines are completely equivalent and have exactly the same effect.  Each get method returns an unnamed temporary copy of str_, whose value is assigned to b (which is not const).

So far, the application of the const qualifier to the return type has no effect, apart from stylistic preference.  However it does make a difference in the following:

( a.get_str() ).erase();            // silly, but legal
( a.get_const_str() ).erase();  // illegal

The latter is illegal because you can't call string::erase() for a const string.

This example is a bit lame because I can't imagine why anyone would want to erase an unnamed temporary string like this.  However there are cases where you may want to disallow non-const methods on such a temporary.  Don't ask me for an example.  I vaguely remember seeing such a situation in one of Scott Meyer's books, or maybe it was Herb Sutter, but I don't remember what the context was.

A similar situation may arise like this:

void capitalize( string & s );
capitalize( a.get_str() );            // silly, but legal
capitalize( a.get_const_str() );  // illegal

Thus there are cases where the constness of a return value can make a difference.  In practice those cases are fairly rare, and usually people don't apply the const qualifier to an object returned by value.

Scott McKellar
http://home.swbell.net/mck9/ct/

Scott McKellar
Friday, September 12, 2003

"
This would tell the programmer that the private member variable I'm accessing with my "get" method is constant.  So, it never changes.  This may/may not be helpful.  Who knows?
"

Just to clear up a common mis-conception: "const" does not mean constant -- it means read-only (un.

For instance:

/* ptr to read-only variable */
const int *variablep;

It is perfectly possible for the value "*variable" to be modified elsewhere by something with a non-readonly pointer to it. (For instance by another thread/processor, or by DMA for memory-mapped hardware.).

MugsGame
Friday, September 12, 2003

"Thus there are cases where the constness of a return value can make a difference."

Yes.  It makes a big difference if your code returns an auto_ptr, since const auto_ptrs cannot transfer ownership.  eg,

//  eg
const auto_ptr<x> foobar( ) const { ... }

//  eg caller
const auto_ptr<x> y = foobar( );  // is illegal

If your code simply returned a non-const auto_ptr<x>, then it could transfer ownership of that pointer to the caller (!!!!).  But with const, you can only look at its pointer value:

//  Legal
foobar( ).get( );

smkr45
Friday, September 12, 2003

I wonder if this would help

class Fred
{
  public:
  const Barney verb () ;
}

In otherwords, Fred::verb may modify the physical state of Fred, and returns a Barney that the caller may not modify.

You certainly can do that. 

It's a bit weird, though.  Why are you trying to restrict what the client can do with his own copy of a Barney?  Especially since the client can (generally) copy the const Barney that you gave him into his own non-const Barney, and change that.  So what are you hoping to prevent?

One possibility is that, for some reason, you don't want to allow chaining of a mutable method.

Fred f ;
f.verb().barney_verb();

Off the top of my head, I can't think of any cases where the standard library returns a const object.  Const pointers, const references, even const_iterators (which, you'll note, isn't const itself, but enforces a contract between the caller and the iterator target) can be found.

Danil
Friday, September 12, 2003

from smkr45:

[begin quote]

If your code simply returned a non-const auto_ptr<x>, then it could transfer ownership of that pointer to the caller (!!!!).  But with const, you can only look at its pointer value:

//  Legal
foobar( ).get( );

[end quote]

Yes, you can call get() on the temporary auto_ptr, but the resulting pointer will be either NULL or invalid.

As soon as the unnamed temporary auto_ptr goes out of scope, its destructor will run, deleting anything that the auto_ptr points to.  The same would be true of a non-const auto_ptr.

You might try to call a member function through such a temporary autoptr:

foobar()->do_something();

...however I think the auto_ptr's destructor would run *before* the call to do_something().  If so, then returning a const auto_ptr by value accomplishes nothing useful.  However I'm not enough of a language lawyer to know for sure exactly when the destructor runs.

On the other hand, returning a non-const auto_ptr by value can be very useful.  You can either ignore it, in which case the auto_ptr's destructor deletes the underlying pointer, or capture it by an assignment.  Doing anything else with the unnamed temporary may invite problems.

Scott McKellar
http://home.swbell.net/mck9/ct/

Scott McKellar
Friday, September 12, 2003

I don't think this was brought up in the thread, but one (most times unimportant) fact to remember when concidering whether to use const or not is that there are situations in which compilers can perform optimizations if they know that a value will never change once instantiated.

Timothy Flechtner
Friday, September 12, 2003

"I think the auto_ptr's destructor would run *before* the call to do_something().  "

s/think/guess/;

Don't guess, look it up.  The destructor isn't going to run until the end of the lifetime of the temporary object, so what you need to learn is when that lifetime ends.


Again, this is mostly moot - why on earth would you ever surrender ownership of an resource, but try to prevent the caller from acquiring ownership? 

Danil
Friday, September 12, 2003

*  Recent Topics

*  Fog Creek Home