What exactly do "IB" and "UB" mean?
IB: Implementation-defined Behaviour. The standard leaves it up to the particular compiler/platform to define the precise behaviour, but requires that it be defined.
Using implementation-defined behaviour can be useful, but makes your code less portable.
UB: Undefined Behaviour. The standard does not specify how a program invoking undefined behaviour should behave. Also known as "nasal demons" because theoretically it could make demons fly out of your nose.
Using undefined behaviour is nearly always a bad idea. Even if it seems to work sometimes, any change to environment, compiler or platform can randomly break your code.
Implementation-defined behavior and Undefined behavior
The C++ standard is very specific about the effects of various constructs, and in particular you should always be aware of these categories of trouble:
Undefined behavior means that there are absolutely no guarantees given. The code could work, or it could set fire to your harddrive or make demons fly out your nose. As far as the C++ language is concerned, absolutely anything might happen. In practical terms, this generally means that you have an unrecoverable bug. If this happens, you can't really trust anything about your application (because one of the effects of this undefined behavior might just have been to mess up the memory used by the rest of your app). It's not required to be consistent, so running the program twice might give different results. It may depend on the phases of the moon, the color of the shirt you're wearing, or absolutely anything else.
Unspecified behavior means that the program must do something sane and consistent, but it is not required to document this.
Implementation-defined behavior is similar to unspecified, but must also be documented by the compiler writers. An example of this is the result of a
reinterpret_cast
. usually, it simply changes the type of a pointer, without modifying the address, but the mapping is actually implementation-defined, so a compiler could map to a completely different address, as long as it documented this choice. Another example is the size of an int. The C++ standard doesn't care if it is 2, 4 or 8 bytes, but it must be documented by the compiler
But common for all of these is that they're best avoided. When possible, stick with behavior that is 100% specified by the C++ standard itself. That way, you're guaranteed portability.
You often have to rely on some implementation-defined behavior as well. It may be unavoidable, but you should still pay attention to it, and be aware that you're relying on something that may change between different compilers.
Undefined behavior, on the other hand, should always be avoided. In general, you should just assume that it makes your program explode in one way or another.