Implementing atomic<T>::store - c++

I'm attempting to implement the atomic library from the C++0x draft. Specifically, I'm implementing §29.6/8, the store method:
template <typename T>
void atomic<T>::store(T pDesired, memory_order pOrder = memory_order_seq_cst);
The requirement states:
The order argument shall not be memory_order_consume, memory_order_acquire, nor memory_order_acq_rel.
I'm not sure what to do if it is one of these. Should I do nothing, throw an exception, get undefined behavior, or do something else?
P.S.: "C++0X" looks kinda like a dead fish :3

Do what you want. It doesn't matter.
When ISO state that you "shall not do something", doing it is undefined behaviour. If a user does that, they have violated the contract with the implementation, and the implementation is within its rights to do as it pleases.
What you decide to do is entirely up to you. I would opt for whatever makes your implementation "better" (in your eyes, be that faster, more readable, subject to the principle of least astonishment, and so forth).
Myself, I'd go for readability (since I would have to maintain the thing) with speed taking a close second.

I prefer a compile time error. If not that, then an assert() failure.
Assert is good because it compiles out of the release version and will not impact performance.
Compile time errors are even better because they provide more immediate feedback without waiting for the software to trip over the bug. Compile time error checks are a thing I love about C++ code over Python, Ruby, Perl code.

I'd rather get vaguey sane behaviour that something crazy.
Well, as a potential consumer of your library, here's what I'd like: if there's no performance cost to the documented usage, then see if one of the memory_order values provides a functional superset of the others, particularly something corresponding to what a caller might naively expect the unsupported modes to do (if any sensible expectation can be formed). The caller may get the slowest, safest mode, but that's better than something functionally wrong. You minimise the client code's dependency on getting everything perfect for your code. The problem with this - compared to an assert/exception - is that it can go unnoticed in a test environment, so consider also writing an explanation to std::cerr, using a static variable to limit the messages to one per process run. That's a very useful diagnostic.
An exception, fatal assertion etc. might bring down a client application at a very inconvenient moment.... Seems a bit draconian, and not something I'd appreciate particularly. Another option is to have an environment variable control this behaviour.
(There's presumably a similar issue for values that aren't even in your current enumeration.)

Related

If you're in the "we don't use exceptions" camp, then how do you use the standard library?

Note: I'm not playing the devil's advocate or anything like that here - I'm just genuinely curious since I'm not in this camp myself.
Most types in the standard library have either mutating functions that can throw exceptions (for instance if memory allocation fails) or non-mutating functions that can throw exceptions (for instance out of bounds indexed accessors). In addition to that, many free functions can throw exceptions (for instance operator new and dynamic_cast<T&>).
How do you practically deal with this in the context of "we don't use exceptions"?
Are you trying to never call a function that can throw? (I can't see how that'd scale, so I'm very interested to hear how you accomplish this if this is the case)
Are you ok with the standard library throwing and you treat "we don't use exceptions" as "we never throw exceptions from our code and we never catch exceptions from other's code"?
Are you disabling exception handling altogether via compiler switches? If so, how do the exception-throwing parts of the standard library work?
EDIT Your constructors, can they fail, or do you by convention use a 2-step construction with a dedicated init function that can return an error code upon failure (which the constructor can't), or do you do something else?
EDIT Minor clarification 1 week after the inception of the question... Much of the content in comments and questions below focus on the why aspects of exceptions vs "something else". My interest is not in that, but when you choose to do "something else", how do you deal with the standard library parts that do throw exceptions?
I will answer for myself and my corner of the world. I write c++14 (will be 17 once compilers have better support) latency critical financial apps that process gargantuan amounts of money and can't ever go down. The ruleset is:
no exceptions
no rtti
no runtime dispatch
(almost) no inheritance
Memory is pooled and pre-allocated, so there are no malloc calls after initialization. Data structures are either immortal or trivially copiable, so destructors are nearly absent (there are some exceptions, such as scope guards). Basically, we are doing C + type safety + templates + lambdas. Of course, exceptions are disabled via the compiler switch. As for the STL, the good parts of it (i.e.: algorithm, numeric, type_traits, iterator, atomic, ...) are all useable. The exception-throwing parts coincide with the runtime-memory-allocating parts and the semi-OO parts nicely so we get to get rid of all the cruft in one go: streams, containers except std::array, std::string.
Why do this?
Because like OO, exception offers illusory cleanliness by hiding or moving the problem elsewhere, and makes the rest of the program harder to diagnose. When you compile without "-fno-exceptions", all your clean and nicely behaved functions have to endure the suspicion of being failable. It is much easier to have extensive sanity checking around the perimeter of your codebase, than to make every operation failable.
Because exceptions are basically long range GOTOs that have an unspecified destination. You won't use longjmp(), but exceptions are arguably much worse.
Because error codes are superior. You can use [[nodiscard]] to force calling code to check.
Because exception hierarchies are unnecessary. Most of the time it makes little sense to distinguish what errored, and when it does, it's likely because different errors require different clean-up and it would have been much better to signal explicitly.
Because we have complex invariants to maintain. This means that there are code, however deep down in the bowels, that need to have transnational guarantees. There are two ways of doing this: either you make your imperative procedures as pure as possible (i.e.: make sure you never fail), or you have immutable data structures (i.e.: make failure recovery possible). If you have immutable data structures, then of course you can have exceptions, but you won't be using them because when you will be using sum types. Functional data structures are slow though, so the other alternative is to have pure functions and do it in an exception-free language such as C, no-except C++, or Rust. No matter how pretty D looks, as long as it isn't cleansed of GC and exceptions, it's an non-option.
Do you ever test your exceptions like you would an explicit code path? What about exceptions that "can never happen"? Of course you don't, and when you actually hit those exceptions you are screwed.
I have seen some "beautiful" exception-neutral code in C++. That is, it performs optimally with no edge cases regardless of whether the code it calls uses exceptions or not. They are really hard to write and I suspect, tricky to modify if you want to maintain all your exception guarantees. However, I have not seen any "beautiful" code that either throws or catches exceptions. All code that I have seen that interacts with exceptions directly have been universally ugly. The amount of effort that went into writing exception-neutral code completely dwarfs the amount of effort that was saved from the crappy code that either throws or catches exceptions. "Beautiful" is in quotes because it is not actual beauty: it is usually fossilized because editing it requires the extra burden of maintaining exception-neutrality. If you don't have unit tests that deliberately and comprehensively misuse exceptions to trigger those edge cases, even "beautiful" exception-neutral code decays into manure.
In our case, we disable the exceptions via the compiler (e.g -fno-exceptions for gcc).
In the case of gcc, they use a macro called _GLIBCXX_THROW_OR_ABORT which is defined as
#ifndef _GLIBCXX_THROW_OR_ABORT
# if __cpp_exceptions
# define _GLIBCXX_THROW_OR_ABORT(_EXC) (throw (_EXC))
# else
# define _GLIBCXX_THROW_OR_ABORT(_EXC) (__builtin_abort())
# endif
#endif
(you can find it in libstdc++-v3/include/bits/c++config on latest gcc versions).
Then you juste have to deal with the fact that exceptions thrown just abort. You can still catch the signal and print the stack (there is a good answer on SO that explains this), but you have better avoid this kind of things to happen (at least in releases).
If you want some example, instead of having something like
try {
Foo foo = mymap.at("foo");
// ...
} catch (std::exception& e) {}
you can do
auto it = mymap.find("foo");
if (it != mymap.end()) {
Foo foo = it->second;
// ...
}
I also want to point out, that when asking about not using exceptions, there's a more general question about standard library: Are you using standard library when you're in one of the "we don't use exceptions" camps?
Standard library is heavy. In some "we don't use exceptions" camps, like many GameDev companies for example, better suited alternatives for STL are used - mostly based on EASTL or TTL. These libraries don't use exceptions anyway and that's because eighth generation consoles didn't handle them too well (or even at all). For a cutting edge AAA production code, exceptions are too heavy anyway, so it's a win - win scenario in such cases.
In other words, for many programmers, turning exceptions off goes in pair with not using STL at all.
Note I use exceptions... but I have been forced not to.
Are you trying to never call a function that can throw? (I can't see how that'd scale, so I'm very interested to hear how you accomplish this if this is the case)
This would probably be infeasible, at least on a large scale. Many functions can land up throwing, avoid them entirely cripples your code base.
Are you ok with the standard library throwing and you treat "we don't use exceptions" as "we never throw exceptions from our code and we never catch exceptions from other's code"?
You pretty much have to be ok with that... If the library code is going to throw an exception and your code is not going to handle it, termination is the default behaviour.
Are you disabling exception handling altogether via compiler switches? If so, how does the exception-throwing parts of the standard library work?
This is possible (back in the day it was sometime popular for some project types); compilers do/may support this, but you will need to consult their documentation for what the result(s) would and could be (and what language features are supported under those conditions).
In general, when an exception would be thrown, the program would need to abort or otherwise exit. Some coding standards still require this, the JSF coding standard comes to mind (IIRC).
General strategy for those who "don't use exceptions"
Most functions have a set of preconditions that can be checked for before the call is made. Check for those. If they are not met, then don't make the call; fall back to whatever the error handling is in that code. For those functions that you can't check to ensure the preconditions are met... not much, the program will likely abort.
You could look to avoid libraries that throw exceptions - you asked this in the context of the standard library, so this doesn't quite fit the bill, but it remains an option.
Other possible strategies; I know this sounds trite, but pick a language that doesn't use them. C could do nicely...
...crux of my question (your interaction with the standard library, if any), I'm quite interested in hearing about your constructors. Can they fail, or do you by convention use a 2-step construction with a dedicated init function that can return an error code upon failure (which the constructor can't)? Or what's your strategy there?
If constructors are used, there are generally two approaches that are used to indicate the failure;
Set an internal error code or enum to indicate the failure and what the failure is. This can be interrogated after the object's construction and appropriate action taken.
Don't use a constructor (or at least only construct what cannot fail in the constructor - if anything) and then use an init() method of some sort to do (or complete) the construction. The member method can then return an error if there is some failure.
The use of the init() technique is generally favored as it can be chained and scales better than the internal "error" code.
Again, these are techniques that come from environments where exceptions do not exist (such as C). Using a language such as C++ without exceptions limits its usability and the usefulness of the breadth of the standard library.
Not trying to fully answer the questions you have asked, I will just give google as an example for code base which does not utilize exceptions as a mechanism to deal with errors.
In Google C++ code base, every functions which may fail return a status object which have methods like ok to specify the result of the callee.
They have configurated GCC to fail the compilation if the developer ignored the return status object.
Also, from the little open source code they provide (such as LevelDB library), it seems they are not using STL that much anyway, so exception handling become rare. as Titus Winters says in his lectures in CPPCon, they "Respect the standard, but don't idolize it".
I think this is an attitude question. You need to be in the camp of "I don't care if something fails".
This usually results in code, for which one needs a debugger (at the customer site) to find out, why suddenly something is not working anymore.
Also potentially people which are doing software "engineering" in this way, do not use very complex code. E.g. one would be unable to write code, which relies on the fact that it is only executed, if all n resources it relies on have been successfully allocated (while using RAII for these resources).
Thus: Such coding would result in either:
an unmanageable amount of code for error handling
an unmanageable amount of code to avoid executing code, which relies on successful allocation of some resources
no error handling and thus considerable higher amount of support and developer time
Note, that I'm talking about modern code, loading customer-provided dlls on demand and using child processes. There are many interfaces on which something can fail. I'm not talking about some replacement for grep/more/ls/find.

Is undefined behavior only an issue if you are deploying on several platforms?

Most of the conversations around undefined behavior (UB) talk about how there are some platforms that can do this, or some compilers do that.
What if you are only interested in one platform and only one compiler (same version) and you know you will be using them for years?
Nothing is changing but the code, and the UB is not implementation-defined.
Once the UB has manifested for that architecture and that compiler and you have tested, can't you assume that from then on whatever the compiler did with the UB the first time, it will do that every time?
Note: I know undefined behavior is very, very bad, but when I pointed out UB in code written by somebody in this situation, they asked this, and I didn't have anything better to say than, if you ever have to upgrade or port, all the UB will be very expensive to fix.
It seems there are different categories of Behavior:
Defined - This is behavior documented to work by the standards
Supported - This is behavior documented to be supported a.k.a
implementation defined
Extensions - This is a documented addition, support for low level
bit operations like popcount, branch hints, fall into this category
Constant - While not documented, these are behaviors that will
likely be consistent on a given platform things like endianness,
sizeof int while not portable are likely to not change
Reasonable - generally safe and usually legacy, casting from
unsigned to signed, using the low bit of a pointer as temp space
Dangerous - reading uninitialized or unallocated memory, returning
a temp variable, using memcopy on a non pod class
It would seem that Constant might be invariant within a patch version on one platform. The line between Reasonable and Dangerous seems to be moving more and more behavior towards Dangerous as compilers become more aggressive in their optimizations
OS changes, innocuous system changes (different hardware version!), or compiler changes can all cause previously "working" UB to not work.
But it is worse than that.
Sometimes a change to an unrelated compilation unit, or far away code in the same compilation unit, can cause previously "working" UB to not work; as an example, two inline functions or methods with different definitions but the same signature. One is silently discarded during linking; and completely innocuous code changes can change which one is discarded.
The code that is working in one context can suddenly stop working in the same compiler, OS and hardware when you use it in a different context. An example of this is violating strong aliasing; the compiled code might work when called at spot A, but when inlined (possibly at link-time!) the code can change meaning.
Your code, if part of a larger project, could conditionally call some 3rd party code (say, a shell extension that previews an image type in a file open dialog) that changes the state of some flags (floating point precision, locale, integer overflow flags, division by zero behavior, etc). Your code, which worked fine before, now exhibits completely different behavior.
Next, many kinds of undefined behavior are inherently non-deterministic. Accessing the contents of a pointer after it is freed (even writing to it) might be safe 99/100, but 1/100 the page was swapped out, or something else was written there before you got to it. Now you have memory corruption. It passes all your tests, but you lacked complete knowledge of what can go wrong.
By using undefined behavior, you commit yourself to a complete understanding of the C++ standard, everything your compiler can do in that situation, and every way the runtime environment can react. You have to audit the produced assembly, not the C++ source, possibly for the entire program, every time you build it! You also commit everyone who reads that code, or who modifies that code, to that level of knowledge.
It is sometimes still worth it.
Fastest Possible Delegates uses UB and knowledge about calling conventions to be a really fast non-owning std::function-like type.
Impossibly Fast Delegates competes. It is faster in some situations, slower in others, and is compliant with the C++ standard.
Using the UB might be worth it, for the performance boost. It is rare that you gain something other than performance (speed or memory usage) from such UB hackery.
Another example I've seen is when we had to register a callback with a poor C API that just took a function pointer. We'd create a function (compiled without optimization), copy it to another page, modify a pointer constant within that function, then mark that page as executable, allowing us to secretly pass a pointer along with the function pointer to the callback.
An alternative implementation would be to have some fixed size set of functions (10? 100? 1000? 1 million?) all of which look up a std::function in a global array and invoke it. This would put a limit on how many such callbacks we install at any one time, but practically was sufficient.
No, that's not safe. First of all, you will have to fix everything, not only the compiler version. I do not have particular examples, but I guess that a different (upgraded) OS, or even an upgraded processor might change UB results.
Moreover, even having a different data input to your program can change UB behavior. For example, an out-of-bound array access (at least without optimizations) usually depend on whatever is in the memory after the array.
UPD: see a great answer by Yakk for more discussion on this.
And a bigger problem is optimization and other compiler flags. UB may manifest itself in a different ways depending on optimization flags, and it's quite difficult to imagine somebody to use always the same optimization flags (at least you'll use different flags for debug and release).
UPD: just noticed that you did never mention fixing a compiler version, you only mentioned fixing a compiler itself. Then everything is even more unsafe: new compiler versions might definitely change UB behavior. From this series of blog posts:
The important and scary thing to realize is that just about any
optimization based on undefined behavior can start being triggered on
buggy code at any time in the future. Inlining, loop unrolling, memory
promotion and other optimizations will keep getting better, and a
significant part of their reason for existing is to expose secondary
optimizations like the ones above.
This is basically a question about a specific C++ implementation. "Can I assume that a specific behavior, undefined by the standard, will continue to be handled by ($CXX) on platform XYZ in the same way under circumstances UVW?"
I think you either should clarify by saying exactly what compiler and platform you are working with, and then consult their documentation to see if they make any guarantees, otherwise the question is fundamentally unanswerable.
The whole point of undefined behavior is that the C++ standard doesn't specify what happens, so if you are looking for some kind of guarantee from the standard that it's "ok" you aren't going to find it. If you are asking whether the "community at large" considers it safe, that's primarily opinion based.
Once the UB has manifested for that architecture and that compiler and you have tested, can't you assume that from then on whatever the compiler did with the UB the first time, it will do that every time?
Only if the compiler makers guarantee that you can do this, otherwise, no, it's wishful thinking.
Let me try to answer again in a slightly different way.
As we all know, in normal software engineering, and engineering at large, programmers / engineers are taught to do things according to a standard, the compiler writers / parts manufacturers produce parts / tools that meet a standard, and at the end you produce something where "under the assumptions of the standards, my engineering work shows that this product will work", and then you test it and ship it.
Suppose you had a crazy uncle jimbo and one day, he got all his tools out and a whole bunch of two by fours, and worked for weeks and made a makeshift roller coaster in your backyard. And then you run it, and sure enough it doesn't crash. And you even run it ten times, and it doesn't crash. Now jimbo is not an engineer, so this is not made according to standards. But if it didn't crash after even ten times, that means it's safe and you can start charging admission to the public, right?
To a large extent what's safe and what isn't is a sociological question. But if you want to just make it a simple question of "when can I reasonably assume that no one would get hurt by me charging admission, when I can't really assume anything about the product", this is how I would do it. Suppose I estimate that, if I start charging admission to the public, I'll run it for X years, and in that time, maybe 100,000 people will ride it. If it's basically a biased coin flip whether it breaks or not, then what I would want to see is something like, "this device has been run a million times with crash dummies, and it never crashed or showed hints of breaking." Then I could quite reasonably believe that if I start charging admission to the public, the odds that anyone will ever get hurt are quite low, even though there are no rigorous engineering standards involved. That would just be based on a general knowledge of statistics and mechanics.
In relation to your question, I would say, if you are shipping code with undefined behavior, which no one, either the standard, the compiler maker, or anyone else will support, that's basically "crazy uncle jimbo" engineering, and it's only "okay" if you do vastly increased amounts of testing to verify that it meets your needs, based on a general knowledge of statistics and computers.
What you are referring to is more likely implementation defined and not undefined behavior. The former is when the standard doesn't tell you what will happen but it should work the same if you are using the same compiler and the same platform. An example for this is assuming that an int is 4 bytes long. UB is something more serious. There the standard doesn't say anything. It is possible that for a given compiler and platform it works, but it is also possible that it works only in some of the cases.
An example is using uninitialized values. If you use an uninitialized bool in an if, you may get true or false, and it may happen that it is always what you want, but the code will break in several surprising ways.
Another example is dereferencing a null pointer. While it will probably result in a segfault in all cases, but the standard doesn't require the program to even produce the same results every time a program is run.
In summary, if you are doing something that is implementation defined, then you are safe if you are only developing to one platform and you tested that it works. If you are doing something that is undefined behavior, then you are probably not safe in any case. There may be that it works but nothing guarantees it.
Think about it a different way.
Undefined behavior is ALWAYS bad, and should never be used, because you never know what you will get.
However, you can temper that with
Behavior can be defined by parties other than just the language specification
Thus you should never rely on UB, ever, but you can find alternate sources which state that a certain behavior is DEFINED behavior for your compiler in your circumstances.
Yakk gave great examples regarding the fast delegate classes. In those cases, the author explicitly claims that they are engaging in undefined behavior, according to the spec. However, they then go to explain a business reason why the behavior is better defined than that. For example, they declare that the memory layout of a member function pointer is unlikely to change in Visual Studio because there would be rampant business costs due to incompatibilities which are distasteful to Microsoft. Thus they declare that the behavior is "de facto defined behavior."
Similar behavior can be seen in the typical linux implementation of pthreads (to be compiled by gcc). There are cases where they make assumptions about what optimizations a compiler is allowed to invoke in multithreaded scenarios. Those assumptions are stated plainly in comments in the sourcecode. How is this "de facto defined behavior?" Well, pthreads and gcc go kind of hand in hand. It would be considered unacceptable to add an optimization to gcc which broke pthreads, so nobody will ever do it.
However, you cannot make the same assumption. You may say "pthreads does it, so I should be able to as well." Then, someone makes an optimization, and updates gcc to work with it (perhaps using __sync calls instead of relying on volatile). Now pthreads keeps functioning... but your code doesn't anymore.
Also consider the case of MySQL (or was it Postgre?) where they found a buffer overflow error. The overflow had actually been caught in the code, but it did so using undefined behavior, so the latest gcc started optimizing the entire check out.
So, in all, look for an alternate source of defining the behavior, rather than using it while it is undefined. It is totally legit to find a reason why you know 1.0/0.0 equals NaN, rather than causing a floating point trap to occur. But never use that assumption without first proving that it is a valid definition of behavior for you and your compiler.
And please oh please oh please remember that we upgrade compilers every now and then.
Historically, C compilers have generally tended to act in somewhat-predictable fashion even when not required to do so by the Standard. On most platforms, for example, a comparison between a null pointer and a pointer to a dead object will simply report that they are not equal (useful if code wishes to safely assert that the pointer is null and trap if it isn't). The Standard does not require compilers to do these things, but historically compilers which could do them easily have done so.
Unfortunately, some compiler writers have gotten the idea that if such a comparison could not be reached while the pointer was validly non-null, the compiler should omit the assertion code. Worse, if it can also determine that certain input would cause the code to be reached with an invalid non-null pointer, it should assume that such input will never be received, and omit all code which would handle such input.
Hopefully such compiler behavior will turn out to be a short-lived fad. Supposedly, it's driven by a desire to "optimize" code, but for most applications robustness is more important than speed, and having compilers mess with code that would have limited the damage caused by errant inputs or errand program behavior is a recipe for disaster.
Until then, however, one must be very careful when using compilers to read the documentation carefully, since there's no guarantee that a compiler writer won't have decided that it was less important to support useful behaviors which, though widely supported, aren't mandated by the Standard (such as being able to safely check whether two arbitrary objects overlap), than to exploit every opportunity to eliminate code which the Standard doesn't require it to execute.
Undefined behavior can be altered by things such as the ambient temperature, which causes rotating hard disk latencies to change, which causes thread scheduling to change, which in turn changes the contents of the random garbage that's getting evaluated.
In short, not safe unless the compiler or the OS specifies the behavior (since the language standard didn't).
There is a fundamental problem with undefined behavior of any kind: It is diagnosed by sanitizers and optimizers. A compiler can silently change behavior corresponding to those from one version to another (e.g. by expanding its repertoire), and suddenly you'll have some untraceable error in your program. This should be avoided.
There is undefined behavior that is made "defined" by your particular implementation, though. A left shift by a negative amount of bits can be defined by your machine, and it would be safe to use it there, as breaking changes of documented features occur quite rarely. One more common example is strict aliasing: GCC can disable this restriction with -fno-strict-aliasing.
While I agree with the answers that say that it's not safe even if you don't target multiple platforms, every rule can have exceptions.
I would like to present two examples where I'm confident that allowing undefined / implementation-defined behavior was the right choice.
A single-shot program. It's not a program which is intended to be used by anyone, but it's a small and quickly written program created to calculate or generate something now. In such a case a "quick and dirty" solution can be the right choice, for example, if I know the endianness of my system and I don't want to bother with writing a code which works with the other endianness. For example, I only needed it to perform a mathematical proof to know if I'll be able to use a specific formula in my other, user-oriented program or not.
Very small embedded devices. The cheapest microcontrollers have memory measured in a few hundred bytes. If you develop a small toy with blinking LEDs or a musical postcard, etc, every penny counts, because it will be produced in the millions with a very low profit per unit. Neither the processor nor the code ever changes, and if you have to use a different processor for the next generation of your product, you will probably have to rewrite your code anyway. A good example of an undefined behavior in this case is that there are microcontrollers which guarantee a value of zero (or 255) for every memory location at power-up. In this case you can skip the initialization of your variables. If your microcontroller has only 256 bytes of memory, this can make a difference between a program which fits into the memory and a code which doesn't.
Anyone who disagrees with point 2, please imagine what would happen if you told something like this to your boss:
"I know the hardware costs only $ 0.40 and we plan selling it for $ 0.50. However, the program with 40 lines of code I've written for it only works for this very specific type of processor, so if in the distant future we ever change to a different processor, the code will not be usable and I'll have to throw it out and write a new one. A standard-conforming program which works for every type of processor will not fit into our $ 0.40 processor. Therefore I request to use a processor which costs $ 0.60, because I refuse to write a program which is not portable."
"Software that doesn't change, isn't being used."
If you are doing something unusual with pointers, there's probably a way to use casts to define what you want. Because of their nature, they will not be "whatever the compiler did with the UB the first time".
For example, when you refer to memory pointed at by an uninitialize pointer, you get a random address that is different every time you run the program.
Undefined behavior generally means you are doing something tricky, and you would be better off doing the task another way.
For instance, this is undefined:
printf("%d %d", ++i, ++i);
It's hard to know what the intent would even be here, and should be re-thought.
Changing the code without breaking it requires reading and understanding the current code. Relying on undefined behavior hurts readability: If I can't look it up, how am I supposed to know what the code does?
While portability of the program might not be an issue, portability of the programmers might be. If you need to hire someone to maintain the program, you'll want to be able to look simply for a '<language x> developer with experience in <application domain>' that fits well into your team rather than having to find a capable '<language x> developer with experience in <application domain> knowing (or willing to learn) all the undefined behavior intrinsics of version x.y.z on platform foo when used in combination with bar while having baz on the furbleblawup'.
Nothing is changing but the code, and the UB is not implementation-defined.
Changing the code is sufficient to trigger different behavior from the optimizer with respect to undefined behavior and so code that may have worked can easily break due to seemingly minor changes that expose more optimization opportunities. For example a change that allows a function to be inlined, this is covered well in What Every C Programmer Should Know About Undefined Behavior #2/3 which says:
While this is intentionally a simple and contrived example, this sort of thing happens all the time with inlining: inlining a function often exposes a number of secondary optimization opportunities. This means that if the optimizer decides to inline a function, a variety of local optimizations can kick in, which change the behavior of the code. This is both perfectly valid according to the standard, and important for performance in practice.
Compiler vendors have become very aggressive with optimizations around undefined behavior and upgrades can expose previously unexploited code:
The important and scary thing to realize is that just about any optimization based on undefined behavior can start being triggered on buggy code at any time in the future. Inlining, loop unrolling, memory promotion and other optimizations will keep getting better, and a significant part of their reason for existing is to expose secondary optimizations like the ones above.

When should you not use [[carries_dependency]]?

I've found questions (like this one) asking what [[carries_dependency]] does, and that's not what I'm asking here.
I want to know when you shouldn't use it, because the answers I've read all make it sound like you can plaster this code everywhere and magically you'd get equal or faster code. One comment said the code can be equal or slower, but the poster didn't elaborate.
I imagine appropriate places to use this is on any function return or parameter that is a pointer or reference and that will be passed or returned within the calling thread, and it shouldn't be used on callbacks or thread entry points.
Can someone comment on my understanding and elaborate on the subject in general, of when and when not to use it?
EDIT: I know there's this tome on the subject, should any other reader be interested; it may contain my answer, but I haven't had the chance to read through it yet.
In modern C++ you should generally not use std::memory_order_consume or [[carries_dependency]] at all. They're essentially deprecated while the committee comes up with a better mechanism that compilers can practically implement.
And that hopefully doesn't require sprinkling [[carries_dependency]] and kill_dependency all over the place.
2016-06 P0371R1: Temporarily discourage memory_order_consume
It is widely accepted that the current definition of memory_order_consume in the standard is not useful. All current compilers essentially map it to memory_order_acquire. The difficulties appear to stem both from the high implementation complexity, from the fact that the current definition uses a fairly general definition of "dependency", thus requiring frequent and inconvenient use of the kill_dependency call, and from the frequent need for [[carries_dependency]] annotations. Details can be found in e.g. P0098R0.
Notably that in C++ x - x still carries a dependency but most compilers would naturally break the dependency and replace that expression with a constant 0. But also compilers do sometimes turn data dependencies into control dependencies if they can prove something about value-ranges after a branch.
On modern compilers that just promote mo_consume to mo_acquire, fully aggressive optimizations can always happen; there's never anything to gain from [[carries_dependency]] and kill_dependency even in code that uses mo_consume, let alone in other code.
This strengthening to mo_acquire has potentially-significant performance cost (an extra barrier) for real use-cases like RCU on weakly-ordered ISAs like POWER and ARM. See this video of Paul E. McKenney's CppCon 2015 talk C++ Atomics: The Sad Story of memory_order_consume. (Link includes a summary).
If you want real dependency-ordering read-only performance, you have to "roll your own", e.g. by using mo_relaxed and checking the asm to verify it compiled to asm with a dependency. (Avoid doing anything "weird" with such a value, like passing it across functions.) DEC Alpha is basically dead and all other ISAs provide dependency ordering in asm without barriers, as long as the asm itself has a data dependency.
If you don't want to roll your own and live dangerously, it might not hurt to keep using mo_consume in "simple" use-cases where it should be able to work; perhaps some future mo_consume implementation will have the same name and work in a way that's compatible with C++11.
There is ongoing work on making a new consume, e.g. 2018's http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0750r1.html
because the answers I've read all make it sound like you can plaster
this code everywhere and magically you'd get equal or faster code
The only way you can get faster code is when that annotation allows the omission of a fence.
So the only case where it could possibly be useful is:
your program uses consume ordering on an atomic load operation, in an important frequently executed code;
the "consume value" isn't just used immediately and locally, but also passed to other functions;
the target CPU gives specific guarantees for consuming operations (as strong as a given fence before that operation, just for that operation);
the compiler writers take their job seriously: they manage to translate high level language consuming of a value to CPU level consuming, to get the benefit from CPU guarantees.
That's a bunch of necessary conditions to possibly get measurably faster code.
(And the latest trend in the C++ community is to give up inventing a proper compiling scheme that's safe in all cases and to come up with a completely different way for the user to instruct the compiler to produce code that "consumes" values, with much more explicit, naively translatable, C++ code.)
One comment said the code can be equal or slower, but the poster
didn't elaborate.
Of course annotations of the kind that you can randomly put on programs simply cannot make code more efficient in general! That would be too easy and also self contradictory.
Either some annotation specifies a constrain on your code, that is a promise to the compiler, and you can't put it anywhere where it doesn't correspond an guarantee in the code (like noexcept in C++, restrict in C), or it would break code in various ways (an exception in a noexcept function stops the program, aliasing of restricted pointers can cause funny miscompilation and bad behavior (formerly the behavior is not defined in that case); then the compiler can use it to optimize the code in specific ways.
Or that annotation doesn't constrain the code in any way, and the compiler can't count on anything and the annotation does not create any more optimization opportunity.
If you get more efficient code in some cases at no cost of breaking program with an annotation then you must potentially get less efficient code in other cases. That's true in general and specifically true with consume semantic, which imposes the previously described constrained on translation of C++ constructs.
I imagine appropriate places to use this is on any function return or
parameter that is a pointer or reference and that will be passed or
returned within the calling thread
No, the one and only case where it might be useful is when the intended calling function will probably use consume memory order.

How do you keep track of exception safety guarantees offered by each function

When writing exception safe code, it is necessary to consider the exception safety guarantee (none, basic, strong or no-throw) of all the functions called. Since the compiler offers no help, I was thinking that a function naming convention might be helpful here. Is there any kind of established notational standard indicating the level of exception safety guarantee offered by functions? I was thinking along the lines of something hungarian-like:
void setFooB(Foo const& s); // B, offers basic guarantee
int computeSomethingS(); // S, offers strong guarantee
int getDataNT() throws(); // NT, offers no-throw
void allBetsAreOffN(); // N, offers no guarantee
Edit: I agree with comments that this kind of naming convention is ugly, so allow me to elaborate on my reasons for suggesting in.
Say I refactor some code, and in that process, change the level of exception safety offered by a function. If the guarantee has changed from, say, strong to basic (justified perhaps by improvement in speed), then every function that calls the refactored function must be reconsidered for their exception safety. If the change in guarantee triggered a change in the function name as well, it would allow the compiler to help me out a little bit in at least flagging all uses of the changed function. This was my rationale for suggesting the naming convention above, problematic as it is. This is very similar to const, where a change in the const-ness of a function has cascading effects on other calling functions, but in that situation the compiler gives very effective assistance.
So I guess my question is, what kind of work habits have people developed in order to ensure that code actually fullfills their intended exception guarantees, especially during code maintenance and refactoring.
I usually find myself documenting that in comments (doxygen), excepts the no throw guarantee, that I often tag with the throw() exception specification if and only when sure that the function is guaranteed not to throw, and exception safety is important.
That is, I usually worry more about exceptions in parts of the code where an unhandled exception would cause problems, and deal with that locally (ensure that your code is exception safe by other means, as RAII, performing the work outside and then merging the results with a no throw operation --i.e. no throw swap, which is about the only function that I actively mark as throw().
Other people might have other experiences, but I find that to be sufficient for my daily work.
I don't think you need to do anything special.
The only ones I really document are no-throw and that is because the syntax of the language allows it.
There should be no code in your project that provides no guarantee. So that only leaves strong/basic to document. For these I don't think you need to explicitly call it out as it not really about the methods themselves but the class as a whole (for these two guarantees). The guarantees they provide are really dependent on usage.
I would like to think I provide the strong guarantee on everything (but I don't) sometimes it is too expensive sometimes its just not worth the effort (if things are going to throw they will be destroyed anyway).
I understand your willingness to do well, but I am unsure about such a naming convention.
I am, in general, wary of naming conventions that are not enforced by the language: they are prone to become the greatest liars.
If you truly need such things, my suggestion is to get your hands on a compiler (Clang for example) and add a new set of attributes. Do note that you'll need to edit your Standard Library provided headers, and all 3rd party headers you rely on, to annotate them so that you can get those guarantees from the ground up.
Then you can have the compiler check the annotations (won't be trivial either...), and then the annotations become useful, because they cannot lie.
I am thinking about adding
#par Exception Safety
Strong guarantee
to my javadocs where appropriate.

How to explain undefined behavior to know-it-all newbies?

There'a a handful of situations that the C++ standard attributes as undefined behavior. For example if I allocate with new[], then try to free with delete (not delete[]) that's undefined behavior - anything can happen - it might work, it might crash nastily, it might corrupt something silently and plant a timed problem.
It's so problematic to explain this anything can happen part to newbies. They start "proving" that "this works" (because it really works on the C++ implementation they use) and ask "what could possibly be wrong with this"? What concise explanation could I give that would motivate them to just not write such code?
Undefined means explicitly unreliable. Software should be reliable. You shouldn't have to say much else.
A frozen pond is a good example of an undefined walking surface. Just because you make it across once doesn't mean you should add the shortcut to your paper route, especially if you're planning for the four seasons.
Two possibilities come to my mind:
You could ask them "just because you can drive on the motorway the opposite direction at midnight and survive, would you do it regularly?"
The more involved solution might be to set up a different compiler / run environment to show them how it fails spectacularly under different circumstances.
"Congratulations, you've defined the behavior that compiler has for that operation. I'll expect the report on the behavior that the other 200 compilers that exist in the world exhibit to be on my desk by 10 AM tomorrow. Don't disappoint me now, your future looks promising!"
Simply quote from the standard. If they can't accept that, they aren't C++ programmers. Would Christians deny the bible? ;-)
1.9 Program execution
The semantic descriptions in this International Standard define a parameterized nondeterministic abstract machine. [...]
Certain aspects and operations of the abstract machine are described in this International Standard as implementation-defined (for example, sizeof(int)). These constitute the parameters of the abstract machine. Each implementation shall include documentation describing its characteristics and behavior in these respects. [...]
Certain other aspects and operations of the abstract machine are described in this International Standard as unspecified (for example, order of evaluation of arguments to a function). Where possible, this International Standard defines a set of allowable behaviors. These define the nondeterministic aspects of the abstract machine. [...]
Certain other operations are described in this International Standard as undefined (for example, the effect of dereferencing the null pointer). [ Note: this International Standard imposes no requirements on the behavior of programs that contain undefined behavior. —end note ]
You can't get any clearer than that.
I'd explain that if they didn't write the code correctly, their next performance review would not be a happy one. That's sufficient "motivation" for most people.
Let them try their way until their code will crash during test. Then the words won't be needed.
The thing is that newbies (we've all been there) have some amount of ego and self-confidence. It's okay. In fact, you couldn't be a programmer if you didn't. It's important to educate them but no less important to support them and don't cut their start in the journey by undermining their trust in themselves. Just be polite but prove your position with facts not with words. Only facts and evidence will work.
John Woods:
In short, you can't use sizeof() on a structure whose elements haven't been
defined, and if you do, demons may fly out of your nose.
"Demons may fly out of your nose" simply must be part of the vocabulary of every programmer.
More to the point, talk about portability. Explain how programs frequently have to be ported to different OSes, let alone different compilers. In the real world, the ports are usually done by people other than the original programmers. Some of these ports are even to embedded devices, where there can be enormous costs of discovering that the compiler decided differently from your assumption.
Turn the person into a pointer. Tell them that they are a pointer to a class human and you are invoking the function 'RemoveCoat'. When they are pointing at a person and saying 'RemoveCoat' all is fine. If the person does not have a coat, no worries - we check for that, all RemoveCoat really does is remove the top layer of clothing (with decency checks).
Now what happens if they are pointing somewhere random and they say RemoveCoat - if they are pointing at a wall then the paint might peel off, if they are pointing at a tree the bark might come off, dogs might shave themselves, the USS Enterprise might lower its shields at a critical moment etc!
There is no way of working out what might happen the behaviour has not been defined for that situation - this is called undefined behaviour and must be avoided.
Quietly override new, new[], delete and delete[] and see how long it takes him to notice ;)
Failing that ... just tell him he is wrong and point him towards the C++ spec. Oh yeah .. and next time be more careful when employing people to make sure you avoid a-holes!
One would be...
"This" usage is not part of the language. If we would say that in this case the compiler must generate code that crashes, then it would be a feature, some kind of requirement for the compiler's manufacturer. The writers of the standard did not wanted to give unnecessary work on "features" that are not supported. They decided not to make any behavioral requirements in such cases.
I like this quote:
Undefined behavior: it may corrupt your files, format your disk or send hate mail to
your boss.
I don't know who to attribute this to (maybe it's from Effective C++)?
C++ is not really a language for dilletantes, and simply listing out some rules and making them obey without question will make for some terrible programmers; most of the stupidest things I see people say are probably related to this kind of blind rules following/lawyering.
On the other hand if they know the destructors won't get called, and possibly some other problems, then they will take care to avoid it. And more importantly, have some chance to debug it if they ever do it by accident, and also to have some chance to realize how dangerous many of the features of C++ can be.
Since there's many things to worry about, no single course or book is ever going to make someone master C++ or probably even become that good with it.
Just show them Valgrind.
Compile and run this program:
#include <iostream>
class A {
public:
A() { std::cout << "hi" << std::endl; }
~A() { std::cout << "bye" << std::endl; }
};
int main() {
A* a1 = new A[10];
delete a1;
A* a2 = new A[10];
delete[] a2;
}
At least when using GCC, it shows that the destructor only gets called for one of the elements when doing single delete.
About single delete on POD arrays. Point them to a C++ FAQ or have them run their code through cppcheck.
One point not yet mentioned about undefined behavior is that if performing some operation would result in undefined behavior, a standards-conforming implementation could legitimately, perhaps in an effort to be 'helpful' or improve efficiency, generate code which would fail if such an operation were attempted. For example, one can imagine a multi-processor architecture in which any memory location may be locked, and attempting to access a locked location (except to unlock it) will stall until such time as the location in question was unlocked. If the locking and unlocking were very cheap (plausible if they're implemented in hardware) such an architecture could be handy in some multi-threading scenarios, since implementing x++ as (atomically read and lock x; add one to read value; atomically unlock and write x) would ensure that if two threads both performed x++ simultaneously, the result would be to add two to x. Provided programs are written to avoid undefined behavior, such an architecture might ease the design of reliable multi-threaded code without requiring big clunky memory barriers. Unfortunately, a statement like *x++ = *y++; could cause deadlock if x and y were both references to the same storage location and the compiler attempted to pipeline the code as t1 = read-and-lock x; t2 = read-and-lock y; read t3=*t1; write *t2=t3; t1++; t2++; unlock-and-write x=t1; write-and-unlock y=t2;. While the compiler could avoid deadlock by refraining from interleaving the various operations, doing so might impede efficiency.
Turn on malloc_debug and delete an array of objects with destructors. freeing a pointer inside the block should fail. Call them all together and demonstrate this.
You'll need to think of other examples to build your credibility until they understand that they are newbies and there's a lot to know about C++.
Tell them about standards and how tools are developed to comply with the standards. Anything outside the standard might or might not work, which is UB.
Just because their program appears to work is a guarantee of nothing; the compiler could generate code that happens to work (how do you even define "work" when the correct behavior is undefined?) on weekdays but formats your disk on weekends. Did they read the source code to their compiler? Examine their disassembled output?
Or remind them just because it happens to "work" today is no guarantee of it working when you upgrade your compiler version. Tell them to have fun finding whatever subtle bugs creep up from that.
And really, why not? They should be providing a justifiable argument to use undefined behavior, not the other way around. What reason is there to use delete instead of delete[] other than laziness? (Okay, there's std::auto_ptr. But if you're using std::auto_ptr with a new[]-allocated array, you probably ought to be using a std::vector anyway.)
Both the C and C++ Standards use the term "Undefined Behavior" to refer to situations in which it may be useful for different implementations to process constructs in differing, incompatible, fashions, some of which will behave predictably but some of which may not. Both use the same terminology to describe UB, and while I don't know of any published Rationale for C++ Standards, the Rationale for the C Standard says:
Undefined behavior gives the implementor license not to catch certain program errors that are difficult to diagnose. It also identifies areas of possible conforming language extension: the implementor may augment the language by providing a definition of the officially undefined behavior."
Note that many actions which were classified as Undefined Behavior by the C Standard were considered fully defined on many if not all implementations, but the authors of the Standard wanted to give implementors targeting unusual platforms or application fields the ability to deviate from the normal behaviors if doing so would benefit their customers. Such freedom was not intended to invite arbitrary and capricious deviations from precedent that make it harder for programmers to quickly and easily do what needed to be done.
Unfortunately, many programmers who use gcc and clang don't understand their needs as well as the maintainers of those compilers, who recognize that that since the Standard avoids mandating anything that would impair the efficiency of applications that will never receive maliciously-crafted inputs, or will only run in contexts where even malicious programs would be unable to damage anything, that implies that there's no need for any implementations to allow programmers to easily and efficiently write programs that are suitable for use in other contexts.