A lot of people are saying
"volatile member function is completely analogous to how const works."
They are quite similar in the sense of if a pointer is marked as const/volatile, it can only access member functions marked as const/volatile.
But actually defining a member function as const has an additional effect, which makes the function read-only. Any modifications of the object inside the function will cause a compiler error. Is there such analogs in volatile member function?
Well, a volatile member function will make the object members volatile, that is, this will be as if it were defined volatile T * const this. And as a consequence, any reference to a member variable is also volatile.
Remember that volatile read/writes are operations that cannot be elided/reordered by the compiler. They are usually used to implement memory-mapped hardware devices or things like that.
Frankly speaking I've never been a use of this feature, other than doing smart tricks to filter the access to the function, not to make use of the volatile-ness of the object. If your code is low level enough to need volatile you probably will want to go putting the volatile just in the variables you need.
Short answer: yes.
If an instance of an object is declared volatile then it is an error to call non-volatile methods on it (or for those methods to call other non-volatile methods).
A non-volatile instance can still call volatile methods, but not that it is perfectly legal to have two otherwise identical methods in a class - one volatile and one not. In that case a non-volatile instance will call the non-volatile version of the method.
But actually defining a member function as const has an additional effect, which makes the function read-only.
That's a bit of a misconception. It doesn't make the member function read-only - it makes *this const. There's a small, but important, difference between the two (the member function can still modify mutable members, and if it wants to be nasty, it can cast away the const-ness of *this to modify anything it wants, and the compiler won't complain).
And a volatile member function works in the exact same way - it makes *this volatile.
Related
This question already has answers here:
Meaning of 'const' last in a function declaration of a class?
(12 answers)
Closed 5 years ago.
What exactly does the const keyword in C++ mean when it's written at the end of a member function (after the argument list)?
It means that *this is const inside that member function, i.e. it doesn't alter the object.
The keyword this is a prvalue expression whose value is the address of the object for which the function is called. The type of this in a member function of a class X is X*. If the member function is declared const, the type of this is const X*. [section 9.3.2 §1]
In a const member function, the object for which the function is called is accessed through a const access path; therefore, a const member function shall not modify the object and its non-static data members. [section 9.3.2 §2]
This means that a const member function can be called on a const instance of the class. A non-const member function can't be called on [1]a const object, since it could potentially try to modify it.
[1] Note: a temporary is not a const object unless it's of const type.
const at the end of a function signature means that the function should assume the object of which it is a member is const. In practical terms it means that you ask the compiler to check that the member function does not change the object data in any way. It means asking the compiler to check that it doesn't directly change any member data, and it doesn't call any function that itself does not guarantee that it won't change the object.
When you create a const object you are asking the compiler to make sure that that object does not change beyond its initialization. That in turns means that the compiler will check you don't directly change its member data and that you don't call any function that does not guarantee it won't change the object.
This is all part of the const correctness philosophy. In essence it means that if things work right now and they won't change then they will never break. In other words, constant things are easier to work with reliably. This const thing at the end of function signatures is a tool for you to prohibit things from breaking. This in turns means you should put const everywhere you possibly can.
Compiler optimizations are possible, but the main benefit is in enforcing the contract expressed in the function's declaration - if you define a member function as const, the compiler prevents any modification to the object inside that function.
You can exempt individual fields in the class from this restriction using mutable in their declaration. This is useful for example when you have a class that encapsulates its own lock_guard, which must change its value to enforce thread safety even within const member functions.
Are there any scenarios where a const variable member is useful in C++?
If you want to make an immutable class, the usual approach is to declare private members with get-only const functions to access their values. This has the advantage that the class can be copy assigned and so on. So in this case you don't need const variable members.
On the other hand, if the class has a const member variable, it won't get an automatic copy assignment operator. I don't see an scenario where this would be useful.
A main advantage of a const data member is the same as with a reference member (indeed a reference can be usefully thought of as a const pointer), namely that it forces initialization, unless the member is of a type with a user-defined default constructor. The compiler will insist on initialization. Still, I've never found that so useful that I've started doing it.
An alternative, if guaranteed initialization is what one desires, is to wrap the data member in a class that does not provide default construction. With this approach the data member can be assigned to, if it supports assignment.
Another advantage (of a const data member) is that it expresses an intended constraint, with compiler checking, and that's almost always good. The more constraints on how values can change, the less there is to consider to understand or debug the code.
Once you initialize a variable const then you never can re-initialized it. Each later attempt to re-initialize the const variable will produce a compilation error.
It is helpful when you want to prevent the accidental modification of some variable which you never want to be change. Like in mathematics we need PI, we can declared it as a constant -
private const double PI = 3.1416;
I went through the already existing thread on this topic and wasn't convinced with the explanation.
What I could pick up from there was:
When a non-static member function is declared const, the restriction is imposed on this this pointer. As static member functions donot involve the this pointer, they cannot be declared const.
Is that it? Doesn't sound too convincing to me. I mean, I'm not questioning why it's so. I just want to to the reason why.
A const non-static member function is allowed to modify local, static, and global variables; it just isn't allowed to modify members of its class through the this pointer (implicitly or explicitly). A const static member function, therefore, would be allowed to modify local, static, and global variables, just like a non-member function. This would make the const meaningless.
If you want to write a function that isn't allowed to modify any non-local variables at all, you can declare it constexpr, although that also imposes additional restrictions.
The reason the const/non-const distinction for functions is important is that there are contexts in which it is not legal to call a non-const function. So the distinction can be used to enforce invariants.
For example, if you pass a non-const reference to a function, if your class is properly designed, you are guaranteed that the function can't change the value of the thing the reference refers to. This allows you to avoid copies.
Also, a non-const reference can't bind to a temporary. This permits functions to signal whether they return values through references or just take a value. You will get an error at compile time if you inadvertently ignore a returned value because a temporary was created unexpectedly.
None of this would apply to static functions because there is no context in which you would be prohibited from calling them. So the entire rationale for the distinction does not exist with static functions.
Why can't a volatile object call a non-volatile member function?
In case of const, it makes sense that calling a non-const member function violates the constness of the the object and hence it is prohibited. But why in the case of volatile?
In case of const, it makes sense that calling a non-const member function violates the const-ness of the the object and hence it is prohibited. But why in the case of volatile?
It's just the same for volatile. Volatile means every access to an object is a visible side effect and cannot be eliminated. If you called a nonvolatile method on a volatile object, you would violate this property (because the nonvolatile method would treat the object just as a normal object). Therefore, it is impossible.
From the standard:
7.1.5.1. If an attempt is made to refer to an object defined with a volatile-quailified type through the use of an lvalue with a
non-volatile-quailified type, the program behaviour is undefined.
I'm guessing your compiler posts an error to prevent undefined behavior. The standard stating so should be reason enough.
The volatile qualifier works much in the same way as const works. To see what can be done thanks to this, take a look at this Alexandrescu article.
That article should also give you some insight into the why.
If you have a class member function marked volatile, is it possible to cast away volatile on a class member when it's bein used within that function?
Yes. To cast away the volatile-ness of an object, const_cast is used:
T & t = const_cast<T&>(volatile_t);
This is the way. But whether you should use it in your code or not, I cannot say without looking at the code. In general, casting away the const-ness as well as volatile-ness, is a dangerous idea, and should be done only after very careful examination of all cases.
You can cast away volatile from any context by using const_cast. You are asking precisely about casting away inside a volatile member, but that does not make any difference.
The volatile in the function is a check that tells the compiler not to complain if you try to call that method on a volatile object (or through a reference or pointer to volatile object), which is unrelated to the volatile-ness of the members.
What I am trying to say is that if you expect the behavior while accessing data members to be consistent with volatile semantics just because the code is inside a volatile member method, that won't happen.