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.
Related
When a class member cannot have a sensible meaning at the moment of construction,
I don't initialize it. Obviously that only applies to POD types, you cannot NOT
initialize an object with constructors.
The advantage of that, apart from saving CPU cycles initializing something to
a value that has no meaning, is that I can detect erroneous usage of these
variables with valgrind; which is not possible when I'd just give those variables
some random value.
For example,
struct MathProblem {
bool finished;
double answer;
MathProblem() : finished(false) { }
};
Until the math problem is solved (finished) there is no answer. It makes no sense to initialize answer in advance (to -say- zero) because that might not be the answer. answer only has a meaning after finished was set to true.
Usage of answer before it is initialized is therefore an error and perfectly OK to be UB.
However, a trivial copy of answer before it is initialized is currently ALSO UB (if I understand the standard correctly), and that doesn't make sense: the default copy and move constructor should simply be able to make a trivial copy (aka, as-if using memcpy), initialized or not: I might want to move this object into a container:
v.push_back(MathProblem());
and then work with the copy inside the container.
Is moving an object with an uninitialized, trivially copyable member indeed defined as UB by the standard? And if so, why? It doesn't seem to make sense.
Is moving an object with an uninitialized, trivially copyable member indeed defined as UB by the standard?
Depends on the type of the member. Standard says:
[basic.indet]
When storage for an object with automatic or dynamic storage duration is obtained, the object has an indeterminate value, and if no initialization is performed for the object, that object retains an indeterminate value until that value is replaced ([expr.ass]).
If an indeterminate value is produced by an evaluation, the behavior is undefined except in the following cases:
If an indeterminate value of unsigned ordinary character type ([basic.fundamental]) or std::byte type ([cstddef.syn]) is produced by the evaluation of:
the second or third operand of a conditional expression,
the right operand of a comma expression,
the operand of a cast or conversion ([conv.integral], [expr.type.conv], [expr.static.cast], [expr.cast]) to an unsigned ordinary character type or std::byte type ([cstddef.syn]), or
a discarded-value expression,
then the result of the operation is an indeterminate value.
If an indeterminate value of unsigned ordinary character type or std::byte type is produced by the evaluation of the right operand of a simple assignment operator ([expr.ass]) whose first operand is an lvalue of unsigned ordinary character type or std::byte type, an indeterminate value replaces the value of the object referred to by the left operand.
If an indeterminate value of unsigned ordinary character type is produced by the evaluation of the initialization expression when initializing an object of unsigned ordinary character type, that object is initialized to an indeterminate value.
If an indeterminate value of unsigned ordinary character type or std::byte type is produced by the evaluation of the initialization expression when initializing an object of std::byte type, that object is initialized to an indeterminate value.
None of the exceptional cases apply to your example object, so UB applies.
with memcpy is UB?
It is not. std::memcpy interprets the object as an array of bytes, in which exceptional case there is no UB. You still have UB if you attempt to read the indeterminate copy (unless the exceptions above apply).
why?
The C++ standard doesn't include a rationale for most rules. This particular rule has existed since the first standard. It is slightly stricter than the related C rule which is about trap representations. To my understanding, there is no established convention for trap handling, and the authors didn't wish to restrict implementations by specifying it, and instead opted to specify it as UB. This also has the effect of allowing optimiser to deduce that indeterminate values will never be read.
I might want to move this object into a container:
Moving an uninitialised object into a container is typically a logic error. It is unclear why you might want to do such thing.
The design of the C++ Standard was heavily influenced by the C Standard, whose authors (according to the published Rationale) intended and expected that implementations would, on a quality-of-implementation basis, extend the semantics of the language by meaningfully processing programs in cases where it was clear that doing so would be useful, even if the Standard didn't "officially" define the behavior of those programs. Consequently, both standards place more priority upon ensuring that they don't mandate behaviors in cases where doing so might make some implementations less useful, than upon ensuring that they mandate everything that should be supported by quality general-purpose implementations.
There are many cases where it may be useful for an implementation to extend the semantics of the language by guaranteeing that using memcpy on any valid region of storage will, at worst, behave in a fashion consistent with populating the destination with some possibly-meaningless bit pattern with no outside side effects, and few if any where it would be either easier or more useful to have it do something else. The only situations where anyone should care about whether the behavior of memcpy is defined in a particular situation involving valid regions of storage would be those in which some alternative behavior would be genuinely more useful than the commonplace one. If such situations exist, compiler writers and their customers would be better placed than the Committee to judge which behavior would be most useful.
As an example of a situation where an alternative behavior might be more useful, consider code which uses memcpy to copy a partially-written structure, and then uses it to make two copies of that structure. In some cases, having the compiler only write the parts of the two destination structures which had been written in the original may improve efficiency, but that behavior would be observably different from having the first memcpy behave as though it stores some bit pattern to its destination. Note that while such a change would not adversely affect a program's overall behavior if no copies of the uninitialized parts of the structure are ever used in a way that would affect behavior, the Standard has no nice way of distinguishing scenarios that could or could not occur under such a module, and thus leaves all such scenarios undefined.
Consider following:
int *volatile x;
(void)x;
GCC (from 5.x to 7.x) complains about it when -Wall is enabled:
warning: 'x' is used uninitialized in this function [-Wuninitialized]
The clang is silent about it.
For some reason, removing the volatile eliminates the warning.
Does the standard say that casting a volatile pointer even to void is undefined, while casting a normal pointer is fine? Or is that a GCC bug?
Disclaimer: The question is tagged as C/C++ on purpose. The GCC gives the same warning for both languages, and I'm interested of there is any difference.
One of the behaviours of volatile for plain old data type like int * is to prevent the compiler from optimizing away the reading and writing to the variable. Please notice that int * here could be whatever like float or int.
So (void)x is meaning "read x and do nothing with the result" because x is volatile. If you read x and it's not pinned to a fixed position in memory (which the compiler might not know, only the linker does), then you're actually using it uninitialized.
If it's not volatile, although the compiler might read x anyway, it will likely avoid/optimize this (since it's a no-op), and silent the warning.
clang takes the safe road here, and since the linker directive could pin the variable x to some position (without clang knowing about it), consider that it's not worth triggering a warning without more evidence it's an issue.
If the variable is declared volatile then to cast away the volatile, just as it is undefined behaviour to cast away the const from a variable declared const. See Annex J.2 of the C Standard:
The behavior is undefined in the following circumstances:
— An attempt is made to refer to an object defined with a volatile-qualified type through
use of an lvalue with non-volatile-qualified type (6.7.3).
Somewhere I have read and noted down about rules of using volatile are:
Use volatile for variables that might change "unexpectedly".
Use volatile for automatic variables in routines that use setjmp().
To force volatile semantics on a particular access, take the address of the variable and cast it to (volatile WHATEVER *), dereferencing the cast expression to get the value.
Sometimes volatile is a reasonable way to get around problems with code generation in compilers that have conformance problems in some areas, eg, the gcc compiler on x86 with semantics of assigning or casting to double. Don't do this just haphazardly, since if it's unnecessary code quality will very likely go down.
Unless you really know what you're doing and why you're doing it, if you're using volatile you're likely doing something wrong. Try to find another way to solve the problem, and if you still have to use volatile code
up a nice small example and post to comp.lang.c and ask for helpful suggestions.
Any access to a volatile object is part of your program's observable behavior in both C and C++. Observable behavior is an important concept in both C and C++.
Your code formally reads a volatile pointer x. I would guess that GCC considers it a rather serious issue when part of program observable behavior involves an uninitialized value.
The moment you remove volatile, reading of x ceases to be a part of observable behavior. Hence the warning disappears as well.
For C++, this is controlled by [expr]/12, which says that (void) x applies the lvalue-to-rvalue conversion to x (i.e., reads the value of x) only if x is a glvalue of volatile-qualified type. Therefore, if x is volatile-qualified, then (void) x reads its value (which yields an indeterminate value and triggers undefined behavior). If x isn't volatile-qualified, then (void) x doesn't apply the lvalue-to-rvalue conversion and the behavior is well-defined.
If the misaligned pointer is dereferenced, the program may terminate abnormally. On some architectures, the cast alone may cause a loss of information even if the value is not dereferenced if the types involved have differing alignment requirements.
The C Standard, 6.3.2.3, paragraph 7 say's:
A pointer to an object or incomplete type may be converted to a
pointer to a different object or incomplete type. If the resulting
pointer is not correctly aligned for the referenced type, the behavior
is undefined.
It seems like the volatile comparison functions in shared_ptr implementation do not exist.
Does it even make sense to exist?
Essentially no, the standard doesn't cater for comparisons or boolean conversion on a volatile shared_ptr.
The following fails to compile...
auto main() -> int {
volatile shared_ptr<int> a;
if (a == nullptr) // fails
; // empty
if (a) // fails
; // empty
}
You could cast the volatile off (via. a const_cast), but I'm not sure that will have the desired outcome. From the cppreference:
Modifying a const object through a non-const access path and referring to a volatile object through a non-volatile glvalue result in undefined behavior.
In more general terms, in not marking member methods as volatile, the class or library implementors are effectively saying "this is not intended to be use as a volatile object" - if it were, then the appropriate methods or overloads would provide for volatile objects. Similarly, this applies to const, in marking members as const, they are saying "this class can be used as a const object.
Why is the volatile needed, what external sources could be modifying the shared_ptr "without the knowledge of the compiler" (this is one of the uses of volatile)? If there are threading issues, then you would be better served with one the thread library utilities, or if the requirement is simply turning off optimisations, various compilers have mechanisms for this already (pragmas etc.).
Volatile is just an indication to the compiler that the memory may change unexpectedly. Turns off some optimizations. Under the covers its just a memory address.
The shared pointer is just holding/managing the resource. That said, since std::shared_ptr::get() isn't marked volatile, you cannot really use a shared_ptr to manage a volatile pointer in a accessible way.
I'd recommend using a naked pointer, and using scoped exit or the destructer to clean up after it.
If you are using volatile because the pointer may be modified by another thread, you may want to consider using std::atomic instead of volatile. In threading workflows, before std::atomic, pointers that were accessed from other threads were usually marked volatile. That is no longer best practice.
When I today read the C Standard, it says about side effects
Accessing a volatile object, modifying an object, modifying a file, or calling a function
that does any of those operations are all side effects
and the C++ Standard says
Accessing an object designated by a volatile glvalue (3.10), modifying an object, calling a library I/O function, or calling a function that does any of those operations are all side effects
Hence because both forbid unsequenced side effects to occur on the same scalar object, C allows the following, but C++ makes it undefined behavior
int a = 0;
volatile int *pa = &a;
int b = *pa + *pa;
Am I reading the specifications correctly? And what is the reason for the discrepancy, if so?
I don't believe there is an effective variation between C and C++ in this regards. Though the wording on sequencing varies the end result is the same: both result in undefined behaviour (though C seems to indicate the evaluation will suceed but with an undefined result).
In C99 (sorry, don't have C11 handy) paragraph 5.1.2.3.5 specifies:
— At sequence points, volatile objects are stable in the sense that previous accesses are
complete and subsequent accesses have not yet occurred.
Combined with your quote from 5.1.2.3.2 would indicate the value of pa would not be in a stable state for at least one of the accesses to pa. This makes logical sense since the compiler would be allowed to evaluate them in any order, just once, or at the same time (if possible). It doesn't actually define what stable means however.
In C++11 there is explicit reference to unsequenced oeprations at 1.9.13. Then point 15 indicates such unsequenced operations on the same operand is undefined. Since undefined behaviour can mean anything happens it is perhaps strong than C's unstable behaviour. However, in both cases there is no guaranteed result of your expression.
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.