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.
Related
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.
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.
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.
What is the advantage of declaring a member variable as a reference?
I saw people doing that, and can't understand why.
One useful case is when you don't have access to the constructor of that object, yet don't want to work with indirection through a pointer. For example, if a class A does not have a public constructor and your class wants to accept an A instance in its constructor, you would want to store a A&. This also guarantees that the reference is initialized.
A member reference is useful when you need to have access to another object, without copying it.
Unlike a pointer, a reference cannot be changed (accidentally) so it always refers to the same object.
Generally speaking, types with unusual assignment semantics like std::auto_ptr<> and C++ references make it easier to shoot yourself in the foot (or to shoot off the whole leg).
When a reference is used as a member that means that the compiler generated operator= does a very surprising thing by assigning to the object referenced instead of reassigning the reference because references can not be reassigned to refer to another object. In other words, having a reference member most of the time makes the class non-assignable.
One can avoid this surprising behaviour by using plain pointers.
I heard that volatile nature of a variable can be removed using const_cast operator.
In which scenarios we need to remove volatile nature of a variable ?
are there any good use cases ?
Is it dangerours operation, because we declared it as volatile thinking that it would be modified by external factors and removing volatile nature could stop modifications to it. Specially when volatile pointers are registers etc.
The moment you do that, behavior is undefined. Note that removing volatile from an expression that really refers to a non-volatile variable and removing volatile from an expression that refers to a volatile variable are different. The latter thing is what you asked about, and it causes undefined behavior. The Standard laws
If an attempt is made to refer to an object defined with a volatile-qualified type through the use of an lvalue with a non-volatile-qualified type, the program behaviour is undefined.