开发者

Const-correctness for C++ classes

class SomeClass {
  public:
    void Render() const;

  private:
     mutable Cache m_some_cache;
};

Is the class above const-correct? When can I safely say "This operation doesn'开发者_如何学JAVAt change the internal state of an instance"?

In the above example SomeClass is something that renders stuff on the screen. It uses a cache (for example OpenGL buffer objects) to allow faster processing for further calls. So the only thing that changes internally is the cache object. I'm asking myself if a cache already belongs to an internal state of a renderer.

The example is very minimal, but in my real application this goes down a road with many classes, i.e. a lot of Render() calls are involved, and most of them do caching only. But some do also load resources through a resource loader -- is the assumption here still right that a method may be const even if it queries a resource manager for loading a resource?


When we say "the internal state doesn't change" we mean a purely logical thing. It is a logical decision whether changing of m_some_cache changes the object state. Const-correctness is a logical question. So, if you think that from a user's point of view changing m_some_cache doesn't affect the object state (in a logical sense) then the code is const-correct.

In your particular case, I believe it is OK.


Think of it this way. This is perfectly valid:

void Type::print_self () const {
    std::cout << *this << std::endl;
}

You aren't modifying the object itself, so the use of the const qualifier is perfectly valid. This method is modifying std::cout, but that doesn't count as far as the constness of Type::print_self() goes.

That said, mutable Cache looks to me to be a contradiction in terms unless you are only using that Cache element for local storage within Render. If you are truly using it as a cache it seems a bit dubious to qualify this element as mutable. Use it as a cache (e.g., across calls to Render rather than within a call to Render) and you have lied to both the compiler and to the user of the class.

Edit
Per the comments made by the OP, the Render method truly is the graphical equivalent of print_self(). The 'real' state of the object (presumably not shown for the sake of constructing a minimal working example) presumably isn't modified by rendering. Designating Render as a const method is the right thing to do. If the Cache data member reason for being is to serve as speed bump that avoids the cost of constructing and destructing it with each call to Render there is nothing wrong with qualifying that Cache member as mutable (which is needed so that Render can remain const).


When can I safely say "This operation doesn't change the internal state of an instance"?

This question is of logical matter. Usually mutable members are not considered as the internal state, but rather as an implementation artifact. So, the documentation of your class generally should describe what is considered to be the internal state, it can leave alone the mutable members.

const concerns only the internal state of the object. const-methods can legitimately alter external state. Here the pointer analogy comes to mind: char * const p is a constant pointer but it can alter the pointed-to value. So your example with resource manager seems correct too.


As @ildjarn observed, const-correctness refers to the observable, not the internal state of an object; that's why mutable is useful.

Then again, if you're actually rendering things, then the observable state of an object representing the screen cannot reasonably be const, IMHO, since it would break if you later added an inspection method to find out what is on-screen/in the frame buffer.

If SomeClass does not represent the screen, then I would expect Render to take a mutable reference to, say, a Screen object as an argument. Logically, something has to change, even if it isn't the SomeClass instance.


The question to ask yourself is, "does calling the Render function change the defined state or future behavior of the object, as far as users are concerned?"

Assuming that your cache really is just a resource cache, then presumably modifying the cache doesn't change the functional behavior, just makes it potentially faster. Since your class doesn't offer a guarantee of how slow it is, that doesn't change the defined state or behavior as far as callers are concerned. So it's a valid candidate for a mutable member, to be modified by const member functions.


Const-correctness is about the state of the object as seen from the outside.

If all calls to member functions continue to return the same result, the object's state is logically the same.

0

上一篇:

下一篇:

精彩评论

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

最新问答

问答排行榜