Avatar of mrwad99
mrwad99Flag for United Kingdom of Great Britain and Northern Ireland

asked on 

Valid use of the keyword mutable?

Ah hello.

I would like opinions on the use of the keyword mutable, and whether or not how I have used it, described below, is valid.  Please consider the pseudo code below:
class CStore
{
public:
	CObject* GetObject(const std::string& strName)
	{
		SortAlphabetically();
		
		// Retrieve item "strName" using lower_bound() or equivalent
	}
	void SortAlphabetically()
	{
		// Sorts m_storage alphabetically
	}

private:
	std::vector<CObject*> m_storage;
};

Open in new window


OK.  I had code similar to the above, and was looking to tidy it up.  I had the brainwave that GetObject() should be const; after all, it does not modify the object in any way.  I then had to make SortAlphabetically() const for obvious reasons.

This lead to a problem.  GetObject() should be const; but should SortAlphabetically() really also be const?  I did some reading and found out about "logical constness" vs "bitwise constness", and realised that SortAlphabetically() could be made const as although it does change the bit-pattern of the CStore object, it would not change the way the object appears to clients (so hence remains logically const).

Feeling appeased, the final piece of the solution was to make m_storage mutable, which I did, then happily continued pounding my keyboard writing new code.

For a short while.

A little nag came into my mind; having made m_storage mutable, what was to stop somebody modifying my class and writing a new function like this:
void CStore::DoNothingSpecial() const
{
	m_storage.clear();
}

Open in new window


Eeek!  Because m_storage is mutable it can be adjusted in whatever way required, so client code could call this function assuming nothing about the CStore object will change, but in reality after the call to DoNothingSpecial() it is completely different to before the call.

Am I right to be concerned with the above, or is it assumed that the anyone modifying the class will not do (stupid) things like this?

How would you get around this issue?

TIA
C++

Avatar of undefined
Last Comment
jkr
Avatar of evilrix
evilrix
Flag of United Kingdom of Great Britain and Northern Ireland image

There's a very simple rule of thumb... if the semantics of mutability are not exposed to the externals of the class then it is fine to make something mutable. In other words, mutable should be viewed as a magic trick - an illusion. The mutable entity must never be visible to anything outside the class. As long as this is the case then the smoke and mirrors of mutable maintains its illusion.

Mutable should be used to enforce the contract that your classes interface exposes. For example, if your class needs to track how many times a function is called but that function is const then making it non-const just to perform this internal house-keeping is violating the contract of the interface for no good reason or benefit to the user of the interface.

Does that make sense?
ASKER CERTIFIED SOLUTION
Avatar of jkr
jkr
Flag of Germany image

Blurred text
THIS SOLUTION IS ONLY AVAILABLE TO MEMBERS.
View this solution by signing up for a free trial.
Members can start a 7-Day free trial and enjoy unlimited access to the platform.
See Pricing Options
Start Free Trial
SOLUTION
Avatar of phoffric
phoffric

Blurred text
THIS SOLUTION IS ONLY AVAILABLE TO MEMBERS.
View this solution by signing up for a free trial.
Members can start a 7-Day free trial and enjoy unlimited access to the platform.
Avatar of phoffric
phoffric

BTW, for your particular case in the OP, it is unusual to have a single data member that is mutable.
Avatar of evilrix
evilrix
Flag of United Kingdom of Great Britain and Northern Ireland image

It is? Why?
Avatar of phoffric
phoffric

>> it is unusual to have a single data member that is mutable
>> It is? Why?

The OP code shows a class having a single data member. As jkr noted, " 'GetObject()' isn't really 'const' at all and should not be declared as such". If you provide a brief example of pseudo-code for a class having a single data member (that is not a mutex) and that qualifying the single data member as mutable is usual and beneficial, then I'd like to review it.

If a class has a single data member, then a method will either read it, modify it, or possibly ignore it. If reading or ignoring it, a method can be qualified as const, and having the data member qualified as mutable is meaningless. If the method is writing to the data member, then what is the benefit of marking this method as const and then having to qualify the single data member as mutable?

Limited time - travelling soon - back next week.
Avatar of evilrix
evilrix
Flag of United Kingdom of Great Britain and Northern Ireland image

I guess my point was that it was a bit of a sweeping statement. I don't think there is any sense in generalising in that way.
Avatar of phoffric
phoffric

>> Valid use of the keyword mutable?
>> I would like opinions on the use of the keyword mutable, and whether or not how I have used it, described below, is valid.
I was making first writing a statement on the author's specific example, which then transformed into a sweeping statement, which I think is true and from the general tone of the question, may be useful; but awaiting counters.
Avatar of phoffric
phoffric

Here is a Stroustrup opinion that I just looked up ["The C++ Programming Language, Special Edition", 2000]. Hope the author finds it useful.
Declaring members mutable is most appropriate when (only) part of a representation is allowed to change. If most of an object changes while the object remains logically const, it is often better to place the changing data in a separate object and access it indirectly.
Then, using this design style, he moves the cached Date formatted strings and valid flags to their own class and now mutable is not needed.
SOLUTION
Avatar of evilrix
evilrix
Flag of United Kingdom of Great Britain and Northern Ireland image

Blurred text
THIS SOLUTION IS ONLY AVAILABLE TO MEMBERS.
View this solution by signing up for a free trial.
Members can start a 7-Day free trial and enjoy unlimited access to the platform.
Avatar of mrwad99
mrwad99
Flag of United Kingdom of Great Britain and Northern Ireland image

ASKER

Thanks a lot for all the comments.  I re-evaluated my design and realised that allowing the underlying storage in my CStore class to be changed within a const method is a really bad idea, especially having read all the links that talk about how mutable members are typically those that are for internal housekeeping or similar.
Avatar of evilrix
evilrix
Flag of United Kingdom of Great Britain and Northern Ireland image

So, now the main question is out of the way...

...I am wondering why you are sorting the vector each time you access it? Why not just use a std::map or insert the data into the vector such that it remains sorted?
Avatar of mrwad99
mrwad99
Flag of United Kingdom of Great Britain and Northern Ireland image

ASKER

In order to retrieve an item using lower_bound(), binary_search() or whatever the vector must be sorted.  In reality there is a member variable that records whether or not the vector is sorted, but I didn't show that to keep things simple.

I felt the overhead of using a map was too great, having read about its performance when compared to the binary search functions with a plain vector, so didn't use it.
Avatar of evilrix
evilrix
Flag of United Kingdom of Great Britain and Northern Ireland image

>> the vector must be sorted
No why not just insert into the sorted position?

>> I felt the overhead of using a map was too great
Depends what you mean by too great? In terms of performance of retrieving, it'll be just as fast as a binary search. In terms of inserting, it'll be faster than inserting into a vector to keep it sorted (since the vector will need to shuffle stuff to make space). In terms of memory usage, yes it will use more memory than a vector; however, unless you are planning on storing millions of tiny records it's unlikely to be an overhead you need to worry about.

Don't forget, "premature optimization is the root of all evil!" Implement it using the best data structure for the job and only change it out for something less suitable if profiling demonstrates there is a bottle neck that is not acceptable.
Avatar of mrwad99
mrwad99
Flag of United Kingdom of Great Britain and Northern Ireland image

ASKER

Hmm; OK, I'll have a read of that article.  And for the record, I don't sort each time I insert into the vector, I only sort() when I want to retrieve, if the vector isn't already sorted, which is set to true after any insertion.  So sorting shouldn't really happen that much.
Avatar of jkr
jkr
Flag of Germany image

As a side note, I finally realized when I had to use "mutable" last time (and it's a couple of years ago): That was within the implementations of quite abstract base interfaces I designed a lot earlier, and we were adding reference counting way later on (don't ask why). So, the counter had to work in otherwise "const" methods as well. That's also the only time I used it ;o)
C++
C++

C++ is an intermediate-level general-purpose programming language, not to be confused with C or C#. It was developed as a set of extensions to the C programming language to improve type-safety and add support for automatic resource management, object-orientation, generic programming, and exception handling, among other features.

58K
Questions
--
Followers
--
Top Experts
Get a personalized solution from industry experts
Ask the experts
Read over 600 more reviews

TRUSTED BY

IBM logoIntel logoMicrosoft logoUbisoft logoSAP logo
Qualcomm logoCitrix Systems logoWorkday logoErnst & Young logo
High performer badgeUsers love us badge
LinkedIn logoFacebook logoX logoInstagram logoTikTok logoYouTube logo