开发者

What can a 'const' method change?

C++ methods allow a const qualifier to indicate that the object is not changed by the method. But what does that mean? Eg. if the instance variables are pointers, does it mean that the pointers are not changed, or also that the memory to which they point is not changed?

Concretely, here is a minimal开发者_JAVA技巧 example class

class myclass {
  int * data;

  myclass() {
    data = new int[10];
  }

  ~myclass() {
    delete [] data;
  }

  void set(const int index) const {
    data[index] = 1;
  }
};

Does the method set correctly qualify as const? It does not change the member variable data, but it sure does change the content of the array.


What can a 'const' method change?

Without explicitly casting away constness, a const member function can change:

  • mutable data members, and
  • any data the class has non-const access to, irrespective of whether that data's accessible:
  • via member variables that are pointers or references,
  • via pointers or references passed as function arguments,
  • via pointers or references returned by functions,
  • directly in the namespace or class (for static members) containing it.

These restrictions apply to operations of data members and bases (in the OO sense) too. More explicitly, a const member function operating on *this's data members or bases, when they're of class/struct/union type, can only call their const member functions (if any), and can only write to their mutable data members (if any).

(A const member function can also change any non-const local variables and by-value parameters, but I know that's not what you're interested in).

const data members can call other const member functions, which will have these same abilities and restrictions.

Eg. if the instance variables are pointers, does it mean that the pointers are not changed, or also that the memory to which they point is not changed?

It means the pointers can't be (easily/accidentally) changed. It does not mean that the pointed-to memory can't be changed.

What you've stumbled on is the logical incorrectness of a const function changing pointed-to or referenced data conceptually owned by the object. As you've found, the compiler doesn't enforce the const correctness you may want or expect here. That's a bit dangerous, but means constness doesn't need to be explicitly removed for pointers/references to other objects which may be changed as a side-effect of the const function. For example, a logging object. (Typically, such objects are not logically "owned" by the object whose const function is operating on them.) The key point is that the compiler can't reliably distinguish the type of logical ownership an object has over pointed-to data, so it's got to guess one way or the other and allow the programmer to either override, or not be protected by const-ness. C++ forgoes the protection.

Interesting, I've heard Walter Bright's D language flips this default, making pointed-to data const by default in const functions. That seems safer to me, though it's hard to imagine how often one would end up needing to explicitly cast away constness to allow wanted side-effects, and whether that would feel satisfyingly precise or annoyingly verbose.


Most succinctly, it means that the type of this is const T * inside const member functions, where T is your class, while in unqualified functions it is T *.

Your method set does not change data, so it can be qualified as const. In other words, myclass::data is accessed as this->data and is of type int * const.


There are two aspects to this question:

  1. what does const mean to the compiler?
  2. how does const apply when it cannot be validated by the compiler?

Question 1

The first is rather simple. The compiler validates that no data members are modified (unless they are qualified as mutable). It validates this recursively: for any user-defined types, it checks that no non-const methods are invoked. For built-in types, it validates that they are not assigned.

The transformation for pointers is T* to T*const (const pointer), not const T* (pointer to const). This means that the compiler does not validate that the object pointed to is not modified. Obviously, this leads to question 2.

Question 2

How does const apply when not validate by the compiler? It means whatever it should mean to your application. This is usually referred to as logical const. When to use const with respect to logical const-ness is subject to debate.


const when applied to a method means:

This means that the state of the object will not be changed by the method.
This means any members that are part of the objects state can not be modified, nor can any functions that are not also const be called.

As this relates to pointers. It means the pointer (if it is part of the state) can not be changed. But the object the pointer points at is part of another object so that means you can call non cost methods on this object (as it is not part of the state of this object).


const basically prevents changing the class instance members' values inside the function. This is useful for more clearer interface, but pose restrictions when using inheritance for example. It's sometimes a little bit deceiving (or a lot actually), as in the example you posted.

const would be most appropriate for Get functions, where it is obvious that the caller is reading a value and has no intentions of changing the object state. In this case you would want to limit the inherited implementations as well to adhere to constness, to avoid confusion and hidden bugs when using polymorphism.

For example

class A{
     int i;
   public:
     virtual int GetI() {return i;};
}

class B : public A{
   public:
     int GetI() { i = i*2; return i;}; // undesirable
}

changing A to:

virtual int GetI() const {return i;};

solves the problem.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜