According to C++03, 5.8/2, left-shifting is defined as follows:
The value of E1 << E2 is E1 (interpreted as a bit pattern) left-shifted E2 bit positions; vacated bits are zero-filled. If E1 has an unsigned type, the value of the result is E1 multiplied by the quantity 2 raised to the power E2, reduced modulo ULONG_MAX+1 if E1 has type unsigned long, UINT_MAX+1 otherwise.
What bothers me here is that unsigned types are explicitly mentioned yet signed types are ignored completely. Compare this to 5.8/3 which defines right-shifting:
The value of E1 >> E2 is E1 right-shifted E2 bit positions. If E1 has an unsigned type or if E1 has a signed type and a nonnegative value, the value of the result is the integral part of the quotient of E1 divided by the quantity 2 raised to the power E2. If E1 has a signed type and a negative value, the resulting value is implementation-defined.
In 5.8/3 both signed and unsigned are explicitly mentioned, even signed holding non-negative and signed holding negative values are mentioned separately.
AFAIK when something is not explicitly defined in C++ Standard the behavior is undefined. I've also seen this question, but it focuses on differences between C and C++ and doesn't seem to have an answer everyone would agree upon.
Is left-shifting a signed integer defined in C++03?
See Question&Answers more detail:os