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 const
ness 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.
精彩评论