44 C++11 bugs fixed in Visual Studio 2013
The following bugs which I described in the VS2012 edition of my book, C++11 Rocks, have been fixed in Visual Studio 2013, so you have more freedom to use C++11 features as they were intended to be used. If you used workarounds for these bugs, now you can remove them and clean up your code!
However, as I was researching VS2013, I was disappointed to learn that many bugs migrated from VS2012 unscathed, and new bugs have been introduced too. I’m working on describing these bugs in the VS2013 edition of C++11 Rocks.
Read on to find out which VS2012 bugs have been fixed!
No more type argument limits on variadic templates
This fixes a whole set of variadic templates in the standard library. As Visual Studio 2013 supports variadic templates, things like std::function
or make_shared
no longer have a limit on the number of template arguments they can take. There used to be a max of about 5 arguments by default in Visual Studio 2012.
Fixed type inference bugs
auto lost alignment specifiers
If you used auto to declare a variable of a type that’s qualified with __declspec(align(...))
, the qualifier may not have been preserved in VS2012, which resulted in incorrect alignment and subsequent crashes.
decltype wasn’t always allowed in place of a type
Even though decltype
is considered to be a type specifier, and the intention is for you to be able to use decltype(expr)
in place of a type name anywhere, VS2012 didn’t allow code like this:
declval caused compilation errors
Some correct code failed to compile in VS2012 because of declval
internals (using add_rvalue_reference
template).
Suppose you want to define an is_comparable<T>
template:
This didn’t compile because declval
failed to handle T.
Fixed smart pointer bugs
Using a lambda as a custom deleter for unique_ptr breaks conversion to bool
If you used a lambda as a custom deleter in VS2012, and specified the type of the lambda as the deleter type (using decltype
), you weren’t able to use the pointer in a boolean context:
Calling unique_ptr::reset could cause a double delete
The order of operations in the reset
method didn’t follow the order prescribed by the standard before VS2013. This could result in a double delete. The following (contrived) example shows how this happened:
The call to reset
invokes SelfReferential
’s destructor, which in turns calls reset
again. The double delete happened because the reset
method reset the pointer to the owned object after deleting it instead of before.
shared_ptr, protected destructor and nullptr
You could’t construct a shared_ptr
of a class with a protected destructor with nullptr
:
In Visual Studio 2013, this code compiles as expected.
Fixed bugs in the type traits library
Wrong answers given for functions
is_function
yielded the wrong result if given a function with too many arguments:
It also incorrectly yielded false for functions with a non-default calling convention.
Similarly, is_member_function_pointer
failed to detect member functions with an explicitly specified calling convention.
is_member_pointer
, in contrast, failed to detect a __cdecl
member:
is_object
was defined in terms of is_function
, so it produced an incorrect result (falsely detecting an object) if it was given a function with too many arguments (i.e. a function which also tripped up is_function
as described above).
is_scalar refused to acknowledge nullptr_t
is_scalar<nullptr_t>
incorrectly returned false in VS2012 – the standard requires nullptr_t
to be considered a scalar type.
is_pod misidentified void
is_pod<void>
incorrectly returned true in VS2012, even though void isn’t a POD type.
is_constructible gave wrong answers for reference types
is_constructible
behaved incorrectly with reference types, returning false for things like this:
Bugs in alignment related type traits
alignment_of
in VS2012 generatee a spurious warning about inaccessible destructor if you used it on a type with a private destructor.
Additionally, the aligned_union
template wasn’t well behaved in VS2012. It returned incorrect results in some cases:
In addition to the member typedef type, aligned_union
is also supposed to have a static member variable alignment_value
containing the value of the strictest alignment of template arguments T1, …, Tn. However, it wasn’t present in the VS2012 implementation.
common_type incorrectly produced void
Instead of failing to compile as the definition of common_type
implies in the standard, it could yield void in VS2012:
common_type
also yielded void incorrectly for user defined types where conversion is possible:
result_of failed to compile in some cases
If you attempt to use move-only argument types with this template in VS2012, you ran into trouble:
Fixed STL container and algorithm bugs
minmax_element algorithm didn’t work
There are two versions of this algorithm defined in the standard:
They should return the first iterator in [first, last) pointing to the smallest element, and the last iterator pointing to the largest element (in terms of comp if supplied), or make_pair(first, first)
if the range is empty. However, in VS2012, it returned make_pair(min_element(first, last), max_element(first, last))
instead.
Containers incorrectly required element move constructors
All of the container move constructors incorrectly require element types to provide a move constructor:
Additionally, they didn’t preserve the allocator during the move operation.
Similarly, map
and unordered_map
element access operators unnecessarily required the value type to be move constructible:
Fixed bugs in concurrency libraries
A bunch of bugs were fixed in the various parts of the concurrency libraries.
shared_future constructed from future
Another bug in VS2012 was in the implementation of the specializations of future
and shared_future
for reference types and void. This bug allowed code like this to compile (which is obviously wrong as future
is a move-only type):
Memory leak in the thread class
There is a bug which could lead to memory leaks being reported on program termination. This was due to the thread constructing and never destroying at_thread_exit_mutex
, as well as some internal allocations in mutex and condition_variable
which could be incorrectly reported as leaks.
Useless wait functions in a future provided by promise
There was a significant downside to using a future
provided by a promise
. Due to a bug in Visual Studio 2012, the wait_for
and wait_until
methods of such future
objects returned future_status::deferred
instead of future_status::timeout
or future_status::ready
, rendering these methods useless.
Incorrect messages in future_error exceptions
There was an off-by-one error between error codes and error messages returned via future_error
, so you couldn’t rely on the message of future_error
. For example, when you got a “broken promise” exception, the message would be “future already retrieved”. The error code was correct, however.
atomic template couldn’t be instantiated with a non-default-constructible type
You received an unwarranted compilation error if you tried to use a type without a default constructor with atomic.
atomics were slow
In VS2012, many atomic operations always enforced sequential consistency, which made them unnecessarily slow. While this didn’t violate the standard, it mostly defeated the purpose of having relaxed memory ordering - as it’s specifically meant to be used where high performance is required. VS2013 provides a different implementation of atomic operations which is much faster.
Fixed random number facility bugs
In debug mode, mersenne_twister_engine
produced an incorrect assert if you tried to use zero as a seed.
The streaming operator for subtract_with_carry_engine
contained an off-by-one error which triggered undefined behavior.
Both independent_bits_engine
and shuffle_order_engine
failed to initialize member variables in their move constructors, which sometimes resulted in infinite loops.
Fixed rational arithmetic library bugs
This library suffered from a remarkable number of defects.
Due to the lack of alias templates in VS2012, you couldn’t write
Instead, you had to refer to the numerator and denominator of the result via the type member:
Another issue was due to how comparison was implemented. It used ratio template arguments instead of using num and den static members as the standard requires. Because of this, if you used non-normalized numerator and denominator as ratio arguments, comparisons would provide an incorrect result:
So in VS2012, you had to make sure the denominator passed to ratio was always a positive number.
Another bug was that ratio_equal
detected inequality but wasn’t very good at detecting equality:
Here is another bug. When you have a ratio<N, D>
, if D is zero or either argument overflowed the boundaries of intmax_t
, then your program is ill-formed. However, Visual Studio 2012 mostly failed to detect these issues:
In the Visual Studio implementation, the static_assert
statements which are supposed to trigger compilation errors in these situations reside in the ratio constructor. However, the compiler only triggers the static_assert
’s in a constructor when the class is instantiated. You wouldn’t normally create instances when using ratio, so be aware that errors won’t be triggered at compile time.
Similarly, some of the operations compile incorrectly when they shouldn’t:
Note that the statement ratio<1, 0>
should actually compile whereas ratio<1, 0>::num
shouldn’t. This is because errors are only detected when one of the members is evaluated.
Other bugs fixed in Visual Studio 2013
tuple_element bounds checking wasn’t done
tuple_element<I, array<T, N>>
is supposed to check that I < N
and fail to compile if it isn’t. This wasn’t done until VS2013.
Wrong conversion to bool for std::function
In some cases, the conversion could produce an incorrect result in VS2012 due to the function object not being empty when it should be. For example:
Assignment to rvalues
Visual Studio 2012 didn’t forbid assignment to rvalues as required by the standard:
align() updated out parameters incorrectly
The function correctly calculated the address it returns, but updated the last two parameters incorrectly:
time_put didn’t work with wchar_t
time_put
didn’t produce output when instantiated with wchar_t
.
Conclusion
For a full list of library changes in VS2013 (not just those related to C++11), you can check out this post by Stephan Lavavej.
In addition to adding new C++11 features, Visual Studio 2013 fixes a significant number of bugs in the existing C++11 functionality in the compiler and libraries, from incorrect compiler errors to memory leaks to poor performance. This is definitely a good thing.
Unfortunately, VS2013 still contains a large number of bugs carried over from VS2012. It also introduces new bugs related to C++11 features. If you don’t want to get stung by these bugs, check out the VS2013 edition of my C++11 Rocks book. Even though it’s currently in beta, it already describes a significant number of Visual Studio bugs.
Keen on mastering C++11/14? I've written books focused on C++11/14 features. You can get a VS2013, Clang or a GCC edition.