Fog Creek Software
Discussion Board




When to use 'const' C++

What is the point of the following use of 'const'?

const int Func(void);

I could see using the 'const' if you were returning a reference or a pointer to a constant object, but on an integral data type it doesn't make sense?  Does it?


Sunday, January 18, 2004

As a member function this asserts that the function itself will not change the object in any way, so the compiler will let you call this member when you only have a const* to the object.

Joel Spolsky
Sunday, January 18, 2004

That would be the case if const were written behind the closing ), wouldn't it?

Sebastian Wagner
Sunday, January 18, 2004

I was under the impression that const at the end implied that, that is:

int Foo() const;

I thought that const before the method name refers to the return value. Am I merely confused?

Mike Swieton
Sunday, January 18, 2004

No, exactly. And yeah, it's a bit pointless writing it before value return types.

Sebastian Wagner
Sunday, January 18, 2004

No, Joel, what you said would be true of

int Func(void) const;

OP, as you said I'm not aware of any reason/meaning for having "const" at the beginning, when the return code is by value (any value, even a struct, not just a int). IMO const at the beginning is meaningful only when the return type is by pointer (e.g. "const int*") or by reference (e.g. "const int&").

Christopher Wells
Sunday, January 18, 2004

The compiler I'm using does not give me any errors or warnings although I have to read up on how to turn up the warning level for VC++ 7.

I would think that if it were meaningless I would recieve an error or a warning such as, 'Meaningless const modifier'.

I agree that the 'const' behind the function definition is what Joel and others describe, but the const in front seems undefined.  I've been looking through 'The C++ Programming Language' to see if Bjarne answers this question but have not found the answer, probably indicating that it is meaningless.


Sunday, January 18, 2004

Also, you shouldn't use "const foobar* method()", as that usage is semi-deprecated because it's ambiguous at times.

The new form ("char const * const") is the preferred method.

Brad Wilson (dotnetguy.techieswithcats.com)
Sunday, January 18, 2004

> Also, you shouldn't use "const foobar* method()", as
> that usage is semi-deprecated because it's ambiguous at
> times.

How is this ambiguous?

(1) It returns a pointer to a "foobar" object.
(2) The data pointed to cannot be modified.
(3) The pointer can be changed to point to another foobar object.

> The new form ("foobar const* const") is the preferred
> method.

This isn't the same thing.

(1) This is a pointer to a "foobar" object.
(2) The data pointed to cannot be modified.
(3) The pointer *cannot* be changed to point to another foobar object.

I can't quite see why you'd want to return this from a function. It's fine for a function to say "here's a pointer to some data I've got, but you can't change the data; look, but don't mess with it".

However, I wouldn't have thought the function had much right to say "ok, here's a pointer to some data, but once you take this pointer, you cannot change it to point to something else".

There is one situation where an immutable pointer is good though and that's when you're defining static data, as in:

namespace
{
    const char* const DEFAULT_FILE = "xyz.txt";
} // anonymous namespace

This says that DEFAULT_FILE points to a character array; you can't modify the data that it points to, and you can't modify DEFAULT_FILE to point to something else. Both desirable and valid things in this context.

Andrew Lighten
Sunday, January 18, 2004

I have a different question. Given the following code:

const int foo();

void test()
{
    int rc1 = foo();
    //int& rc2 = foo();
    const int& rc3 = foo();
}

The statement containing rc2 doesn't compile, with an error message "A reference that is not to 'const' cannot be bound to a non-lvalue".

My question is, given that the rc3 statement is legal, when does the unnamed temporary (the foo return value, to which rc3 is a reference) go out of scope / become invalid? Is the rule for the lifetime of the temporary the same as if it had been named, i.e. is the above above equivalent to the following:

void test()
{
    int rc1 = foo();
    //int& rc2 = foo();
    const int temp = foo();
    const int& rc3 = temp;
}

Christopher Wells
Sunday, January 18, 2004

Oh yeah, I'm dyslexic today.

Joel Spolsky
Sunday, January 18, 2004

> My question is, given that the rc3 statement is legal,
> when does the unnamed temporary (the foo return
> value, to which rc3 is a reference) go out of scope /
> become invalid?

I think the temporary is destroyed when the reference goes out of scope.

The C++ standard (section 12.2) talks about temporary objects. There's a whole bunch of waffle in there, but the relevant details for this situation are paragraph 5, which says, in part:

| The second context is when a reference is bound to a
| temporary. The temporary to which the reference is
| bound or the temporary that is the complete object to a
| subobject of which the temporary is bound persists
| for the lifetime of the reference except as specified
| below.

The "except as specified below" bit goes on to make the following statements:

| A temporary bound to a reference member in
| constructor’s ctorinitializer (12.6.2) persists until the
| constructor exits.

| A temporary bound to a reference parameter in a
| function call (5.2.2) persists until the completion of
| the full expression containing the call.

| A temporary bound to the returned value in a function
| return statement (6.6.3) persists until the function
| exits.

The first two are easy to understand, but I have to admit I can't quite wrap my head around this last one.

Andrew Lighten
Sunday, January 18, 2004

Thanks Andrew.

My guess is that the last one is refering to the test1 function below, and saying that it's a bad idea (because the temporary will disappear when test1 exits and be undefined when it's referenced in test2):

int foo();

const int& test1()
{
    return foo();
}

void test2()
{
  const int& rc = test1();
}

Christopher Wells
Sunday, January 18, 2004

Yeah, that's the way I read it too, and you're right -- the term "bad idea" certainly comes to mind.

Andrew Lighten
Sunday, January 18, 2004

Andrew Lighten:

You are wrong. The 'const' operator always refers to what is at his *left*, the exception when it is at the beggining of the line, so:

const char * blabla;
and:
char const * blabla;

Have exactly the same meaning: the value which is pointed is const, but not the pointer itself.

But:

char * const blabla;

Has non-constant data, but const pointer.

whatever
Monday, January 19, 2004

http://www.parashift.com/c++-faq-lite/const-correctness.html

SteveM
Monday, January 19, 2004

Whatever;

I have no problem with "const char* blabla" and "char const* blabla" being the same thing. I didn't say they aren't. See points 18.8 and 18.9 in the const correctness FAQ that SteveM linked to.

What I said was that "const char* blahblah" and "const char* const blahblah" aren't the same thing. And they're not. See 18.5 in same FAQ.

How was I wrong?

Andrew Lighten
Monday, January 19, 2004

*  Recent Topics

*  Fog Creek Home