C++, casting and const

Started by
17 comments, last by MaulingMonkey 13 years, 8 months ago
Quote:Original post by Shinkage
Edit2: Okay, this too...
Quote:Original post by CmpDev
volatile has nothing todo with threads but that is another topic.

This isn't true either. Volatile specifically says "other threads/processes may modify this" so that the compiler won't screw things up with optimizations.


No, it doesn't. Well, it may but that depends on what compiler / OS you're using.


EDIT: Read the "In C and C++" section of this Wikipedia article. http://en.wikipedia.org/wiki/Volatile_variable
Advertisement
Quote:Original post by RobTheBloke
Quote:Original post by Red Ant
Beware that casting to or from void* is almost never a good idea since it completely chucks type safety out the window.


Uhm. All casts throw away type safety. That's it's purpose in life. To throw away the type safety of the language because *you know better*.... ;)


Casting to/from a void* is much worse since the compiler will also lose any offset-to-virtual-table-pointer information - this makes it possible to cast to "the right type" in the following order and cause pretty spectacular crashes:

1. Derived* to void*
2. void* to Base*
3. Base* to Derived* <- can shift the actual pointer address to account for a vpointer or multiple-inheritance shift.
Quote:Original post by Red Ant
Quote:Original post by Shinkage
Edit2: Okay, this too...
Quote:Original post by CmpDev
volatile has nothing todo with threads but that is another topic.

This isn't true either. Volatile specifically says "other threads/processes may modify this" so that the compiler won't screw things up with optimizations.


No, it doesn't. Well, it may but that depends on what compiler / OS you're using.


EDIT: Read the "In C and C++" section of this Wikipedia article. http://en.wikipedia.org/wiki/Volatile_variable


Okay, well, in GCC and MSVC it works more or less the way I described. It tells the compiler that "this variable may be modified elsewhere" so the compiler doesn't assume it can just stick it in a register and use it from there. Whether that's because it's mapped to the hardware or because another thread does so, the effect is the same. Not really familiar with any compilers that treat it differently from that, but it definitely does have something to do with threading.

Your Wikipedia citation is true, but somewhat irrelevant. I didn't (and wouldn't) claim that volatile can be relied on for atomic access or proper sequencing, just that it is not unrelated to threads, as had been earlier claimed. User beware.
Quote:Original post by Shinkage
Okay, well, in GCC and MSVC it works more or less the way I described. It tells the compiler that "this variable may be modified elsewhere" so the compiler doesn't assume it can just stick it in a register and use it from there. Whether that's because it's mapped to the hardware or because another thread does so, the effect is the same. Not really familiar with any compilers that treat it differently from that, but it definitely does have something to do with threading.

Your Wikipedia citation is true, but somewhat irrelevant. I didn't (and wouldn't) claim that volatile can be relied on for atomic access or proper sequencing, just that it is not unrelated to threads, as had been earlier claimed. User beware.



According to the standard, all volatile does is prevent reordering of instructions that access the variable, and enforces that the variable is read or written to exactly once for every access written in the original code. By the standard, then, volatile indeed has nothing to do with threading.

Anything beyond that is entirely implementation-specific, and the details of how that works may still vary.

For instance, the PowerPC compiler used for the Xbox 360 has no notion of volatile used for threading purposes. Note also that due to things like CPU-level caching, CPU-level instruction reordering within the pipeline, and the way NUMA works, you will not get proper thread safety guarantees even in compilers that claim volatile has some threading-related benefits.

volatile is almost always the wrong thing to use, especially when threading is concerned. Whether or not it has some marginal added semantics in certain compilers does not change this.

Wielder of the Sacred Wands
[Work - ArenaNet] [Epoch Language] [Scribblings]

Quote:Original post by ApochPiQ
According to the standard, all volatile does is prevent reordering of instructions that access the variable, and enforces that the variable is read or written to exactly once for every access written in the original code. By the standard, then, volatile indeed has nothing to do with threading.


Just because the standard doesn't say "threading" doesn't mean its application has nothing to do with threading. As an example, I've used the keyword in one situation where I had a separate thread which could be spawned to emulate a memory-mapped interface to a hardware device for testing purposes (that is, so the software could be tested without the device always being there). It was absolutely "threading related," and absolutely the right thing to use at the time.

But all these arguments are getting silly and pedantic. Somebody said it has "nothing to do with threads," and that is demonstrably false in the general case. It may be true in certain architectures, for certain compilers, but it's misleading and just plain wrong to make the claim as an absolute.

If you're saying you shouldn't be using it for any kind of thread-safety guarantees, you'd be entirely right, but nobody ever said you should, so what's the point?
This has gone far beyond the original question, that said thanks for all the responses. There seems to be alot of disagreement on what reinterpret_cast can safely do. Now I know shouldn't use it, and I don't in normal code, more I was just curious on what it can do. It seems a bit silly that any use of reinterpret_cast would be undefined/implementation specific, but perhaps I'm wrong here?

I was under the impression casting through reinterpret_cast and back, as long as the alignment and size of the intermediate was appropriate, that you can safely (and in a defined/non-implementation specific way) get the original value back (whatever that may be), and use it. For example:

int a = 5;void* b = &aint c = *reinterpret_cast<int*>(b);


is undefined?

Also this one thing piqued my interest:

Quote:Original post by ApochPiQ
volatile is almost always the wrong thing to use, especially when threading is concerned.


If volatile is not to be used for inter-thread communication what do you use?

Whether it be message passing, mutex's, critical sections, barriers, or what-have-you, they all rely on volatile under the hood don't they? Apart from going straight down to assembly or calling as OS supplied routine (both of which are undefined/implementation specific) you don't have a lot of other options.

[Edited by - Ryan_001 on August 28, 2010 7:14:06 PM]
As the documentation indicates, casting back to the original type from void* is perfectly safe and guaranteed to work. Anything else is unsafe.

volatile is not used as a foundation for thread safety primitives. Thread locks, inter-thread/inter-process communication, et. al. require OS-level support. There is no such thing as a portable threading implementation (although portable interfaces such as pthreads and boost's thread library do exist), because under the hood, everything has to have specific support from the multitasking kernel to ensure safety.

Wielder of the Sacred Wands
[Work - ArenaNet] [Epoch Language] [Scribblings]

Quote:Original post by Ryan_001
Whether it be message passing, mutex's, critical sections, barriers, or what-have-you, they all rely on volatile under the hood don't they?

Not necessarily.
Quote:Apart from going straight down to assembly or calling as OS supplied routine (both of which are undefined/implementation specific) you don't have a lot of other options.

No you don't... which is part of the reason that boost's threading library is getting shoved into the standard library of the next revision of C++.
Quote:Original post by Ryan_001
This has gone far beyond the original question, that said thanks for all the responses. There seems to be alot of disagreement on what reinterpret_cast can safely do. Now I know shouldn't use it, and I don't in normal code, more I was just curious on what it can do. It seems a bit silly that any use of reinterpret_cast would be undefined/implementation specific, but perhaps I'm wrong here?

I was under the impression casting through reinterpret_cast and back, as long as the alignment and size of the intermediate was appropriate, that you can safely (and in a defined/non-implementation specific way) get the original value back (whatever that may be), and use it. For example:

int a = 5;void* b = &aint c = *reinterpret_cast<int*>(b);


is undefined?


That should be standard defined -- but you could just use a static_cast there as well. Using char* instead of void* (and adding another reinterpret_cast) I believe would be similarly defined behavior.

However, you shouldn't be too suprised if something is undefined, 'unspecified', or implementation defined in C++. For example, which is called first, a or b, in this statement?
f( a(), b() );
Trick question: It's unspecified, and may actually change depending on compiler settings.

Yes, even this simple kind of thing. It's quite maddening [lol]. To worsen matters, take this bit of code:
f( ++(*a), ++(*b) );
People will infer from the above question that the order in which these two values are incremented is unspecified. But it gets worse: If a and b point to the same int (or other intrinsic type), the behavior is outright undefined behavior. In practice, the optimizer will often increment twice before passing either value to f. In theory, it could do anything -- even crash, corrupt memory, or launch nuclear missiles at a cow ranch in Alaska. All perfectly acceptable behavior according to the C++ standard [lol]

This topic is closed to new replies.

Advertisement