Question

I am missing something or const-correctness doesn't work quite as intended with pointers (or perhaps smart pointers since that is what I've tested?). Anyway, here is what I observed with trying out a variant of the PIMPL idiom.

I have the following declared:

class A {
public:
  A(...);
  ...
  bool update_stuff(...) const;
  ...
protected:
  bool update_stuff_impl(...) const;
  ...
private:
  struct pimpl;
  pimpl* m_pimpl;
};

And for the implementation, I have something like:

struct A::pimpl {
  pimpl(...): some_data(new some_type());
  ...
  some_method1(...); // Modifies content of some_data
  some_method2(...); // Modifies content of some_data 
  ...

  boost::shared_ptr<some_type> some_data;
};

A::A(...): m_pimpl(new pimpl(...)) {
  ...
}

bool A::update_stuff(...) const {
   if( !update_stuff_impl(...) ) {
      return false;
   }
   return true;
}

bool A::update_stuff_impl(...) const {
   //-Change content of pimpl::some_data here
   m_pimpl->some_method1(...);
   m_pimpl->some_method2(...);
   return true;
}

What I'm having trouble understanding is how I could get away with using const qualifier for the functions A::update_stuff(...) and A::update_stuff_impl(...) when I am actually modifying A::pimpl::some_data??! Or is this expected behavior or just plain bad usage? If it is one of the latter, appreciate if you can identify how it can be corrected?

Thanks for your time and interest.

Was it helpful?

Solution

It's not a new discovery, you can read up on something like 'const is shallow' in C++. What leads to natural distinction between physical and logical const (read after the second too).

If you have pointer in class, be it smart or dumb, you're likely involved in this problem and must carefully design. Taking into account that modifying the attached data on the other end of pointer is not discovered.

Possible workararounds are to make the pointer const T* and add private member function that returns T*. Another is to restrict direct access to the pointer in general, and require a pair of functions one const and other nonconst.

OTHER TIPS

C++ protects constness of pimpl* m_pimpl variable. It doesn't allow to change the value of the pointer. But it allows to do anything with the object this pointer is pointing. Generally there is no way to protect it.

For example, consider a class member variables int a; int* b;. In a class member function we can do the following:

int a_copy = a;
a_copy = 42;
int* b_copy = b;
*b_copy = 42;

Here a_copy and b_copy are local variables. They are not protected with constness of the object you're in. So this code can be executed using const method. The difference is that a variable value has not been changed here, and *b value has been changed. Since a pointer can be easily copied, there is no way for a compiler to know if some pointer is equal to any pointer lying in a member value of const object.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top