All entries for February 2010
February 06, 2010
A fun fact that I discovered when developing my physics engine Large Polygon Collider last year: the STL containers that Visual Studio uses are by default offensively slow.
There are three solutions I know of:
1. Use another compiler such as GCC
MinGW is an implementation of the GCC compiler suite for Windows.
It may or may not be possible to use an alternative compiler from within the Visual Studio IDE. I can’t find any references for it, but I have heard (though not tested) that it is possible to set up a project that uses a makefile to build.
Code::Blocks is probably the best alternative IDE to Visual Studio. They also provide a download package which includes MinGW.
Another advantage of switching compiler is that you avoid another issue of Visual Studio: you need to ensure that someone running your application has the Visual C++ Redistributable package installed. But that is another rant for another time.
2. Use another STL implementation such as STLPort
STLPort is an alternative STL implementation. Performance-wise, it should beat the Microsoft implementation, even after fixing that as described below.
3. Change the idiotic Visual Studio behaviour
There are a couple of obscure macros that you must define to disable the runtime safety checks which cause the agonising slowness:
#define _SECURE_SCL 0 #define _HAS_ITERATOR_DEBUGGING 0
You should set these in the project settings, under pre-processor definitions (and make sure to do it in both debug and release mode). Don’t ever do it from a header file unless you’re certain that file will always be included first. So the new set of definitions should look something like this:
I also put this in an always-included header file:
#ifdef _MSC_VER #if( _SECURE_SCL != 0 ) #pragma message( "Warning: _SECURE_SCL != 0. You _will_ get either slowness or runtime errors." ) #endif #if( _HAS_ITERATOR_DEBUGGING != 0 ) #pragma message( "Warning: _HAS_ITERATOR_DEBUGGING != 0. You _will_ get either slowness or runtime errors." ) #endif #endif
Which will give you warnings if the macros aren’t defined.
The reason those warnings talk about runtime errors is because of the catch related to this solution:
If you link with another object/library with those macros defined differently (i.e. the default), you may get runtime errors. The gorey details as descibed in this comment are as follows:
My (not necessarily 100% accurate) summary of those rules:
These are the rules that you must follow when modifying _SECURE_SCL and _HAS_ITERATOR_DEBUGGING:
- They must be consistently defined within each translation unit (i.e. a source file and all of the header files that it includes). For example, you can’t include a Standard header, alter _SECURE_SCL or _HAS_ITERATOR_DEBUGGING, and include another Standard header.
- Translation units that are linked into the same binary (executable or DLL) must have identical definitions of _SECURE_SCL and _HAS_ITERATOR_DEBUGGING. For example, linking one .obj with _SECURE_SCL==0 to another .obj with _SECURE_SCL==1 into an .exe or .dll is bad. For another example, linking several .obj files with _SECURE_SCL==0 into a .lib, and then linking an .obj with _SECURE_SCL==1 against that .lib into an .exe or .dll is bad.
- Binaries that pass STL objects between each other must have identical definitions of _SECURE_SCL and _HAS_ITERATOR_DEBUGGING. (They must also be both retail or both debug.)
You must have the same settings across your entire project and in any libraries you statically link to. Dynamically linked libraries should be fine unless they use STL containers in their public API.
The error message you get if these rules are broken will be beautifully unhelpful and even misleading: so be on your toes.
MSDN page on checked iterators and _SECURE_SCL
MSDN page on debug iterators and _HAS_ITERATOR_DEBUGGING
Blog post discussing the implementation of _SECURE_SCL and _HAS_ITERATOR_DEBUGGING. Comments discuss the runtime error issue.
Video about STL Iterator Debugging and Secure SCL