I want to execute a read-only method on an object marked as const, but in order to do this thread-safely, I need to lock a readers-writer mutex:
const Value Object::list() const {
ScopedRead lock(children_);
...
}
But this breaks because the compiler complains about "children_" being const and such. I went up to the ScopedRead class and up to the RWMutex class (which children_ is a sub-class) to allow read_lock on a const object, but I have to write this:
inline void read_lock() const {
pthread_rwlock_rdlock(const_cast<pthread_rwlock_t*>(&rwlock_));
}
I have always learned that const_cast is a code smell. Any way to avoid this ?
Make the lock mutable
mutable pthread_rwlock_t rwlock;
This is a common scenario in which mutable is used. A read-only query of an object is (as the name implies) an operation that should not require non-const access. Mutable is considered good practice when you want to be able to modify parts of an object that aren't visible or have observable side-effects to the object. Your lock is used to ensure sequential access to the object's data, and changing it doesn't effect the data contained within the object nor have observable side-effects to later calls so it is still honoring the const-ness of the object.
Make the lock mutable.
Yes, use mutable. It's designed for this very purpose: Where the entire context of the function is const (i.e. an accessor or some other logically read-only action.) but where some element of writable access is needed for a mutex or reference counter etc.
The function should be const, even if it does lock a mutex internally. Doing so makes the code thread-neutral without having to expose the details, which I presume is what you're trying to do.
There are very few places where const_cast<> needs to be legitimately used and this isn't one of them. Using const cast on on an object, especially in a const function is a code maintenance nightmare. Consider:
token = strtok_r( const_cast<char*>( ref_.c_str() ), ":", &saveptr );
In fact, I'd argue that when you see const_cast in a const function, you should start by making the function non-const (very soon after you should get rid of the const_cast and make the function const again though)
Well, if we are not allowed to modify the declaration of the variable, then const_cast comes to the rescue. If not, making it mutable is the solution.
To solve the actual problem, declare the lock as mutable.
The following is now my professional opinion:
The compiler is right to complain, and you are right to find this mildly offensive. If performing a read-only operation requires a lock, and locks must be writeable to lock, then you should probably make the read-only query require non-const access.
EDIT: Alright, I'll bite. I've seen this kind of pattern cause major perf hits in places you would not expect. Does anyone here know how tolower or toupper can become a major bottleneck if called frequently enough, even with the default ASCII locale? In one particular implementation of the C runtime library built for multithreading, there was a lock taken to query the current locale for that thread. Calling tolower on the order of 10000 times or more resulted in more of a perf hit than reading a file from disk.
Just because you want read-only access doesn't mean that you should hide the fact that you need to lock to get it.
Related
According to Herb Sutter (http://isocpp.org/blog/2012/12/you-dont-know-const-and-mutable-herb-sutter), in C++11 const methods must not alter the object bit-wise, or must perform internal synchronization (e.g. using a mutex) if they have mutable data members.
Suppose I have a global object that I'm accessing from multiple threads and suppose it has mutable members. For the sake of argument, let's assume that we cannot modify the source of the class (it's provided by a third-party).
In C++98 these threads would use a global mutex to synchronize access to this object. So, an access would require a single mutex lock/unlock.
However, in C++11, any const member function call on this object will invoke internal synchronization as well, so potentially, a single const function call on this object will cost 2 lock/unlock operations (or more, depending on how many functions you call from a single thread). Note that the global mutex is still needed, because const doesn't seem to do anything for writers (except possibly slowing them down as well, if one of the non-const methods calls a const method).
So, my question is: If all of our classes have to be this way in C++ (at least to be usable by STL), doesn't this lead to excessive synchronization measures?
Thanks
Edit: Some clarifications:
It seems that in C++11, you cannot use a class with the standard library unless its const member functions are internally synchronized (or do not perform any writes).
While C++11 doesn't automatically add any synchronization code itself, a standard-library-compliant class doesn't need synchronization in C++98, but needs it in C++11. So, in C++98 you can get away with not doing any internal synchronization for mutable members, but in C++11 you can't.
in C++11, any const member function call on this object will invoke internal synchronization as well
Why? That synchronisation doesn't just magically appear in the class, it's only there if someone adds it explicitly.
so potentially, a single const function call on this object will cost 2 lock/unlock operations
Only if someone has added an internal mutex to it and you also use an external one ... but why on earth would you do that?
Note that the global mutex is still needed, because const doesn't seem to do anything for writers (except possibly slowing them down as well, if one of the non-const methods calls a const method).
If the class has an internal mutex that's used to make the const members thread-safe then it could also be used for non-const members. If the class doesn't have an internal mutex, then the situation is identical to the C++98 one.
I think you're seeing a problem that doesn't exist.
Herb's "new meaning for const" is not enforced by the language or compiler, it's just design guidance, i.e. an idiom for good code. To follow that guidance you don't add mutexes to every class so const members are allowed to modify mutable members, you avoid mutable members! In the rare cases where you absolutely must have mutable members, either require users to do their own locking (and clearly document the class as requiring external synchronisation) or add internal synchronisation and pay the extra cost ... but those situations should be rare, so it's not true that "C++11 objects are slower because of the new const" because most well-designed objects don't have mutable members anyway.
Yes, you are absolutely correct. You should make your objects follow these guidelines, and therefore access to them will potentially be slower in C++11. If and only if:
The class has mutable members which const member functions modify.
The object is being accessed from multiple threads.
If you ensure that at least one of these is untrue, then nothing changes. The number of objects that are being accessed from multiple threads should always be as minimal as possible. And the number of classes that have mutable members should be minimal. So you're talking about a minimal set of a minimal set of objects.
And even then... all that is required is that data races will not be broken. Depending on what the mutable data even is, this could simply be an atomic access.
I fail to see the problem here. Few of the standard library objects will have mutable members. I defy you to find a reasonable implementation of basic_string, vector, map, etc that need mutable members.
It seems that in C++11, you cannot use a class with the standard library unless its const member functions are internally synchronized (or do not perform any writes).
This is incorrect. You most certainly can. What you cannot do is attempt to access that class across multiple threads in a way that would "perform any writes" on those mutable members. If you never access that object through that C++11 class across threads in that particular way, you're fine.
So yes, you can use them. But you only get the guarantees that your own class provides. If you use your class through a standard library class in an unreasonable way (like your const member functions not being const or properly synchronized), then that's your fault, not the library's.
So, in C++98 you can get away with not doing any internal synchronization for mutable members, but in C++11 you can't.
That's like saying you can get away with computer crime back in the Roman Empire. Of course you can. They didn't have computers back then; so they didn't know what computer crime was.
C++98/03 did not have the concept of "threading". Thus, the standard has no concept of "internal synchronization", so what you could or could not "get away with" was neither defined nor undefined. It made no more sense to ask that question of the standard than to ask what the hacking laws were during Ceaser's day.
Now that C++11 actually defines this concept and the idea of a race condition, C++11 is able to say when you can "get away with not doing any internal synchronization".
Or, to put it another way, here is how the two standards answer your question: What is the result of a potential data race on a mutable member when accessed via a member function declared const in the standard library?
C++11: There will be no data races on any internal members when accessed by a const function. All standard library implementations of such functions must be implemented in such a way that a data race cannot occur.
C++98/03: What's a data race?
Say I have the following member function:
void CFoo::regWrite( int addr, int data )
{
reg_write( addr, data ); // driver call to e.g. write a firmware register
}
Clearly, calling this function doesn't modify the internal state of the object it is called on. However, it changes the state of whatever this Foo instance represents.
In circumstances such as these, should Foo::regWrite(int addr, int data) be a const function?
You have to decide what the meaning is of "logically const" for the class CFoo, and that depends what the class is for.
If CFoo is construed as referring to some data, then it might make sense to be able to modify that data via a const instance of CFoo, in which case your member function would be const. For examples of this consider other types that refer to some data -- you can modify the referand of a char *const or a const std::unique_ptr<char>.
If CFoo is construed as owning some data, then it might make sense to forbid modification via a const instance of CFoo. For examples of this consider containers, where the elements are logically "part of the object's state" even when they aren't physically part of the object. So vector::operator[] has a const overload that returns a const T& rather than a T&, the insert member function is non-const, etc.
It is up to the programmer to define what 'const' shall mean for a class. With the specifier mutable you can even have a constobject with changing values in a member. When it comes to hardware one might consider the configuration as the target for const correctness: as long as the configuration does not change the object can be considered constant.
A similar issue rises if you have pointers to other objects in your class: Your const method can then call non-const methods on the other object and thus modifiy it.
If you look at the hardware as as some other object referenced by your class, it would be perfectly valid to modify firmware settings (since only a "referenced" object is changed). If you want your class to "represent" the hardware (or part of it), I would rather suggest not to mark the method as const.
So I think it mainly depends how you designed your class.
There are two ways of looking at this - the optimization angle, and the logic of this declaration. Which is more important is for you to decide.
Optimization
EDIT: I made some incorrect assumptions. It seems the compiler is not actually free to make the optimizations below, and will only make them by analyzing the body of the method to ensure no modifications occur (and even then only in simple cases).
Having this const will allow the compiler to optimize a little bit
more. It knows that regWrite doesn't change any fields in the
object, so it can keep them if it was storing them in registers, and
do similar optimizations that rely on the objects fields not being
changed.
This is really the only thing the compiler will depend on when you
make a definition like this, so having this const is OK and can
theoretically allow better performance.
Making logical sense
It feels unintuitive to have a const method whose whole purpose is a destructive change. The usual intuition a programmer has is that as long as I'm only calling const methods, the results of other const methods shouldn't change. If you violate this unwritten contract, expect people to be surprised - even if the compiler is OK with it.
I'm not sure if this will be violated here - it will depend on the other code in this class. However, if no other considerations are important (performance, etc.), const is (for me) mostly a marker on the interface which says "calling this does not change the state of this object", for a broad definition of "state".
This is murky ground however, and it is up to you what you consider a state change. If you think of your firmware object as representing a link to the internals, writing a register does not change anything about this link and is const. If you think of it as representing the state of the underlying registers, than writing to registers is a change of state.
From my understanding of the mutable keyword, one of its primary uses is caching data and computing them when needed. Since they can change (even though they are const) wouldnt it be unsafe or pointless to use them? The caching part modifies the data so there would need to be a lock and from my understanding when you write for multithreads the data should NEVER change and copies should be made and returned/chained together.
So is it pointless or bad to use C++'s mutable keyword?
So is it pointless or bad to use C++'s mutable keyword?
No; the mutable keyword is A Good Thing. mutable can be used to separate the observable state of an object from the internal contents of the object.
With the "cached data" example that you describe (a very common use of mutable), it allows the class to perform optimizations "under the covers" that don't actually modify the observable state.
With respect to accessing an object from multiple threads, yes, you have to be careful. In general, if a class is designed to be accessed from multiple threads and it has mutable variables, it should synchronize modification of those variables internally. Note, however, that the problem is really more a conceptual one. It's easy to reason that:
All of my threads only call const member functions on this shared object
Const member functions do not modify the object on which they are called
If an object is not modified, I don't need to synchronize access to it
Therefore, I don't need to synchronize access to this object
This argument is wrong because (2) is false: const member functions can indeed modify mutable data members. The problem is that it's really, really easy to think that this argument is right.
The solution to this problem isn't easy: effectively, you just have to be extremely careful when writing multithreaded code and be absolutely certain that you understand either how objects being shared between threads are implemented or what concurrency guarantees they give.
On the opposite end, most of my multithreaded code requires the use of the mutable keyword:
class object {
type m_data;
mutable mutex m_mutex;
public:
void set( type const & value ) {
scoped_lock lock( m_mutex );
m_data = value;
}
type get() const {
scoped_lock lock( m_mutex );
return m_data;
}
};
The fact that the get method does not modify the state of the object is declared by means of the const keyword. But without the mutable modifier applied to the declaration of the mutex attribute, the code would not be able to lock or release the mutex --both operations clearly modify the mutex, even if they do not modify the object.
You can even make the data attribute mutable if it can be lazily evaluated and the cost is high, as long as you do lock the object. This is the cache usage that you refer to in the question.
The mutable modifier is not a problem with multithreaded code, only when you try to do lock-less multithreading. And as with all lock-less programming, you must be very careful with what you do, regardless of const or mutable. You can write perfectly unsafe multithreaded code that calls const methods on objects with no mutable attributes. The simple example would be removing the mutex from the previous code and having N threads perform only get()s while another thread performs set()s. The fact that get() is const is no guarantee that you will not get invalid results if another thread is modifying.
No, the mutable keyword is so that you can have fields inside an object that can change even when the object is const, such as for metadata that isn't part of an object's properties but its management (such as counters, etc.). It has nothing to do with threading.
After reading this, it is my understanding that declaring a method as const prevents it from accidentally modifying the class's member variables.
Are const methods commonly used?
Should they be used for everything that shouldn't modify member variables?
Yes, const should always be used, when appropriate.
It lets your compiler check your application logic, statically asserting const-correctness for free!
Some people even say that const should be the default, and you should be forced to use mutable for what is non-constant.
I use const extensively to communicate design intent. If I intended that a method was a pure query, and not a modification function, I would both enforce that and communicate it with a 'const' in the signature.
I encourage you to look at Meyer's thoughts on the matter of side-effect-free functions, and the implications that has on enabling testing.
Just my testimony.
Some years ago, I was still against the use of const, just because of the constraints in design and writing longer function signatures... and so on...
But one of my project leaders always insisted, all the time, reminding me: "You should use const function, it avoids accidents and doing non-sense".
And one day I faced an impossible bug to find. Days after days after days... A nightmare. The design was too big for me too see so as I could grasp it in its whole. I searched in vain until I decided I was lost.
Then I spent two days redefining ALL the functions that should be const. I mean it, two days. (Recompilations were long as it was a 5 millions lines of code project).
And then: simply I found the bug... rather the Compiler found the bug for me: In a getter-like method, which should have given me the prefered size of a gui control, the code was actually computing the size, but it was also caching its size and updating its size... Thus modifying the object.
Now, sometimes I forget to put const. But if I notice it, I correct it.
Adding const to a member function allows it to be called on const references to an object, because it guarantees that instance variables won't be changed. Const references occur in various places throughout the STL, so it makes sense to mark member functions as const where the function doesn't intend to modify the state of an object.
Note: it is possible to mark certain instance variables as mutable so they can be changed even by const functions. This is useful to implement look-up caches, for example.
Declaring a method that shouldn't modify member variables:
Assures that what you think is what is happening, i.e. that you're not accidentally modifying a variable somewhere.
Declares to callers of the function that this method doesn't modify member variables, removing the need to read over the code or rely on documentation that says so.
So yes, use const wherever it makes sense. They're not as widely used as I'd like to see though, most likely because the majority of developers don't see the huge benefit.
If you forget to mark an accessor as const, the compiler will not allow the method to be called on const objects or references to const objects. So yes, marking accessors as const is important.
If you have a const reference or pointer (i.e. pointer to const) of a class object then you can ONLY call const member methods of the class.
So if someone "forgot" to make a "get" method const, you would not be able to call it with a const reference (There is a workaround with const_cast but we don't want to use that!).
So yes, if the class is not going to be modified by the method then it should be const.
Note: there are some occasions that you do want to modify a variable as an "implementation detail", eg lazy-loading or to lock a mutex. In such a case you can still make the method const but make that member variable "mutable".
If you are writing a virtual method, it should be const if no derived class will need it to be mutable.
You should use the const keyword whenever possible.
It prevent you from the mistakes in the code.
It increase the readability of the code very much.
Everyone who is reading the header and seeing const keywords can immediately understand that a const method does not change the state of an object and can be used with no being afraid he will change the object for example
I'm adding some lazy initialization logic to a const method, which makes the method in fact not const. Is there a way for me to do this without having to remove the "const" from the public interface?
int MyClass::GetSomeInt() const
{
// lazy logic
if (m_bFirstTime)
{
m_bFirstTime = false;
Do something once
}
return some int...
}
EDIT: Does the "mutable" keyword play a role here?
Make m_bFirstTime mutable:
class MyClass
{
: :
mutable bool m_bFirstTime;
};
...but this is also very often an indication of a design flaw. So beware.
Actually, you said that you didn't want to change the header file. So your only option is to cast away the constness of the this pointer...
int MyClass::GetSomeInt() const
{
MyClass* that = const_cast<MyClass*>(this);
// lazy logic
if (that->m_bFirstTime)
{
that->m_bFirstTime = false;
Do something once
}
return some int...
}
If using mutable raises a red flag, this launches a red flag store in to orbit. Doing stuff like this is usually a really bad idea.
I think of this problem as involving two concepts: (1) "logically const" and (2) "bitwise const". By this I mean that getting some int from a class, does not logically change the class and in most cases it does not change the bits of the class members. However, in some cases, like yours, it does.
In these cases, where the method is logically const but not bitwise const, the compiler cannot know this. This is the reason for the existence of the mutable keyword. Use it as John Dibling shows, but it is not a design flaw. On the contrary, there are many cases where this is necessary. In your example, I presume that the calculation of the int is expensive, so we do not want to calculate it if it is not needed. In other cases, you may wish to cache results of methods for later use, etc.
BTW, even though you have accepted the "mutable" answer as correct, you do have to update the .h!
set the m_bFirstTime member to be mutable
As John Dibling said, mark the fields that are changed as mutable. The important part is in the comment by ypnos: 'don't really change the state of the object' (as perceived by the outside world). That is, any method call before and after the const method call must yield the same results. Else your design is flawed.
Some things that make sense to be mutable:
mutex or other lock types
cached results (that will not change)
Mutex are not part of your objects state, they are only a blocking mechanism to guarantee data integrity. A method that will retrieve a value from your class, does need to change the mutex, but your class data and state will be exactly the same after the execution of the const method as it was before.
With caching, you must consider that only data that it makes sense for data that is expensive to retrieve and assumed not to change (DNS result, as an example). Else you could be returning stale data to your user.
Some things that should not be changed inside const methods:
Anything that modifies the state of
the object
Anything that affects this or other
method results
Any user of your class that executes const methods will assume that your class (as seen from the outside world) will not change during the execution. It will be quite misleading and error prone if it were not the same. As an example, assume that a dump() method changes some internal variable -state, value- and that during debug the user of your class decides to dump() your object at a given point: your class will behave differently with traces than without: perfect debug nightmare.
Note that if you do lazy optimizations you must do them to access immutable data. That is, if your interface dictates that during construction you will retrieve an element from the database that can be later accessed through a constant method, then if you do lazy fetching of the data you can end up in a situation where the user constructs your object to keep a copy of the old data, modifies the database and later on decides to restore the previous data into the database. If you have performed a lazy fetch you will end up loosing the original value. An opposite example would be configuration file parsing if the config file is not allowed to be modified during the execution of the program. You can avoid parsing the file up the point where it is needed knowing that performing the read in the beginning or at a later time will yield the same result.
In any case - make note that this is no longer going to be thread safe. You can often rely on an object to be thread safe if it only has const methods (or you use only the const methods after initialization). But if those const methods are only logically const, then you lose that benefit (unless of course you start locking it all the time).
The only compiler optimization that could cause havok would be for the compiler to figure out that you're calling the method twice with the same arguments, and just reuse the first return value - which is fine as long as the function truly is logically const, and returns the same value for a given set of arguments (and object state). Even that optimization isn't valid if it's possible that anyone (including another thread) has had access to the object to call non-const methods on it.
mutable was added to the language specifically for this case. C++ is a pragmatic language, and is happy to allow corner cases like this to exist for when they are needed.