Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why isn't the const qualifier working on pointer members on const objects?

I know this has been asked a lot, but the only answers I could find was when the const-ness was actually casted away using (int*) or similar. Why isn't the const qualifier working on pointer type member variables on const objects when no cast is involved?

#include <iostream>

class bar {
public:
    void doit()       { std::cout << "    bar::doit() non-const\n"; }
    void doit() const { std::cout << "    bar::doit() const\n"; }
};

class foo {
    bar* mybar1;
    bar mybar2;
public:
    foo() : mybar1(new bar) {}
    void doit() const {
        std::cout << "foo::doit() const\n";
        std::cout << "  calling mybar1->doit()\n";
        mybar1->doit();  // This calls bar::doit() instead of bar::doit() const
        std::cout << "  calling mybar2.doit()\n";
        mybar2.doit(); // This calls bar::doit() const correctly
    }
    // ... (proper copying elided for brevity)
};

int main(void)
{
    const foo foobar;  // NOTE: foobar is const
    foobar.doit();
}

The code above yields the following output (tested in gcc 4.5.2 and vc100):

foo::doit() const
  calling mybar1->doit()
    bar::doit() non-const         <-- Why ?
  calling mybar2.doit()
    bar::doit() const
like image 804
Oskar N. Avatar asked May 06 '11 22:05

Oskar N.


People also ask

Why can't you assign a const reference to a non const reference?

Once you have a const object, it cannot be assigned to a non-const reference or use functions that are known to be capable of changing the state of the object. This is necessary to enforce the const-ness of the object, but it means you need a way to state that a function should not make changes to an object.

Where may a const type qualifier appear?

In a function declaration, the keyword const may appear inside the square brackets that are used to declare an array type of a function parameter. It qualifies the pointer type to which the array type is transformed.

What is const type qualifier in C?

The const qualifier explicitly declares a data object as something that cannot be changed. Its value is set at initialization. You cannot use const data objects in expressions requiring a modifiable lvalue. For example, a const data object cannot appear on the lefthand side of an assignment statement. C only.

Can you modify a const pointer C++?

Because the data type being pointed to is const, the value being pointed to can't be changed. We can also make a pointer itself constant. A const pointer is a pointer whose address can not be changed after initialization.

Can a const pointer value be changed?

In constant pointers, the pointer points to a fixed memory location, and the value at that location can be changed because it is a variable, but the pointer will always point to the same location because it is made constant here.

What does const& mean in C++?

The const keyword specifies that a variable's value is constant and tells the compiler to prevent the programmer from modifying it.


2 Answers

When a foo instance is const, its data members are const too, but this applies differently for pointers than you might at first think:

struct A {
  int *p;
};

A const obj;

The type of obj.p is int * const, not int const *; that is, a constant pointer to int, not a pointer to constant int.

For another way to look at it, let's start with a function:

template<class T>
T const& const_(T const &x) {
  return x;
}

Now imagine we have an A instance, and we make it const. You can imagine that as applying const_ on each data member.

A nc;
// nc.p has type int*.
typedef int *T;  // T is the type of nc.p.

T const &p_when_nc_is_const = const_(nc.p);
// "T const" is "int * const".

const T &be_wary_of_where_you_place_const = const_(nc.p);
// "const T" is "int * const".
// "const T" is *not* "const int *".

The variable be_wary_of_where_you_place_const shows that "adding const" is not the same as prepending "const" to the literal text of a type.

like image 76
Fred Nurk Avatar answered Oct 01 '22 15:10

Fred Nurk


I am going to answer my own question in this case. Fred Nurk's answer is correct but does not really explain the "why". mybar1 and *mybar1 are different. The first refer to the actual pointer and the latter the object. The pointer is const (as mandated by the const-ness on foo; you can't do mybar1 = 0), but not the pointed to object, as that would require me to declare it const bar* mybar1. The declaration bar* mybar1 is equivalent to bar* const mybar1 when the foo object is const (i.e. pointer is const, not pointed to object).

like image 36
Oskar N. Avatar answered Oct 01 '22 17:10

Oskar N.