Maxpm
Maxpm

Reputation: 25592

Const Methods that Return References

class Foo
{
    int Bar;

    public:

    int& GetBar() const
    {
        return Bar;
    }
}

Is it okay that GetBar is a const method? It's not actually changing anything, but it's providing the "outside world" with a means of changing it.

Upvotes: 26

Views: 18384

Answers (6)

Matteo Italia
Matteo Italia

Reputation: 126797

No, you can't do that; in a const method you have a const this pointer (in your case it would be a const Foo *), which means that any reference you can get to its fields1 will be a const reference, since you're accessing them through a "const path".

Thus, if you try to do what you did in that code you'll get a compilation error, since you'd be trying to initialize an int & (the return value of your method) with a const int & (the reference you get from Bar), which obviously is forbidden.

g++ actually says:

testconstref.cpp: In member function ‘int& Foo::GetBar() const’:
testconstref.cpp:9: error: invalid initialization of non-const reference of type ‘int&’ from a temporary of type ‘const int*’

which is what I just said. :)

If, instead, you return a const reference to a class field from a const method you'll have no problem.


  1. Excluding fields marked as mutable, which tells to the compiler that such fields are modifiable even from const methods; this exception has been introduced to allow const methods to change the "real" state of the object in cases when this do not alter its "logical" state; this can be useful to implement lazy evaluation, reference counting, ...

Upvotes: 5

Jörgen Sigvardsson
Jörgen Sigvardsson

Reputation: 4887

No, this is not legal. When tagging a method with const, not only are you promising you won't touch any of the internal state of the object, you also promise that you will not return anything that can be used to change the state of the object. A non-const reference may be used to modify the value of Bar outside the scope of GetBar(), hence you are implying that you cannot hold the promise.

You must either change the method to being non-const, return a const reference, or make Bar exempt of the promise by marking it as mutable. E.g.: mutable int Bar; The mutable keyword tells the compiler that the logical constness of the object does not depend on the state of Bar. Then you are allowed to do whatever you please with it.

Upvotes: 31

CashCow
CashCow

Reputation: 31445

The members of your class are considered const when you are in a const method. So although Bar is int within your class and not const int, in the context of GetBar() const it is "const int". Therefore returning it as a non-const reference or pointer is just as illegal as doing:

const int y = 57; int& z = y;

This breaks const-correctness even though the 2nd line has not actually changed anything (yet) in y.

Note incidentally that if your class has pointer members the only thing that is const is the pointers themselves and not what they point to. (Often referred to as "shallow" constness)

Thus this would be legal:

class A
{
  Foo * foo;

  public:
    Foo * getFoo() const // legal. does not have to return const Foo *
    {
       return foo;
    }
};

Note that in your original code you would be allowed to return Bar by non-const reference if it were mutable, because those members are not bound by the constness of member functions.

Upvotes: 2

Mahesh
Mahesh

Reputation: 34625

const modifier to a member function doesn't allow to change the object's state with in it's scope. Compiler just checks whether this function is modifying the state of the object or not in its scope. Taking another example -

class foo
{
    int num ;
    public :
       foo( int anum )
       {
           anum = 10;
       }
       int getNum()
       {
           return num;
       }
 };

 foo obj;
 int& myNum = obj.getNum() ; // myNum is just an alias to the private class variable num
 myNum = 40; // Actually changes the content of the private variable.

So, compiler just checks access specifiers ( i.e., whether this variable is accessible or not in this scope) but not about the private/public/protected variable's memory location if returned to some other variable.

Upvotes: 0

suszterpatt
suszterpatt

Reputation: 8273

You probably want to return Bar, not &Bar. Anyway, I dropped this code in Comeau:

class Foo
{
    int Bar;

    public:

    int& GetBar() const
    {
        return &Bar;
    }
};

int main(int argc, char** argv)
{
  Foo x;
  int y = x.GetBar();
  y = 5;
  return 0;
}

And got the error:

line 9: error: qualifiers dropped in binding reference of type
          "int &" to initializer of type "const int"
          return Bar;
                 ^

Upvotes: 3

Šimon Tóth
Šimon Tóth

Reputation: 36433

Nope, since you cant do the following assignment: const int x; int &y = x;

What you can do though is const int x; const int &y = x;

And of course there is no problem in overloading the method and creating both const and non-const variants.

Upvotes: 5

Related Questions