Q&A on our TR1 implementation

Q&A on our TR1 implementation

Rate This
  • Comments 82

Hello.  My name is Stephan and I’m a developer on the Visual C++ libraries team.  As the Visual Studio 2008 Feature Pack Beta (available for download here with documentation available here) contains an implementation of TR1, I thought I’d answer some common questions about this technology.

 

Q. What version of Visual C++ does the Feature Pack work against?

 

A. The Feature Pack is a patch for the RTM version Visual C++ 2008 (also known as VC9)..  The patch can't be applied to:

 

    * VC9 Express.

    * Pre-RTM versions of VC9 (e.g. VC9 Beta 2).

    * Older versions of VC (e.g. VC8).

 

Q: Can I just drop new headers into VC\include instead of applying the patch?

 

A: No. VC9 TR1 consists of new headers (e.g. <regex>), modifications to existing headers (e.g. <memory>), and separately compiled components added to the CRT (e.g. msvcp90.dll). Because it is mostly but not completely header-only, you must apply the patch and distribute an updated CRT with your application. You can think of VC9 TR1 as "Service Pack 0".

 

Q: If I use TR1, will I gain a dependency on MFC? Or, if I use the MFC updates, will I gain a dependency on TR1?

 

A: No. The TR1 and MFC updates don't interact. They're just being distributed together for simplicity.

 

Q: How complete is your TR1 implementation?

 

A: Our implementation contains everything in TR1 except sections 5.2 and 8 (http://open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1836.pdf ). That is, we are shipping the Boost-derived components and the unordered containers.

 

Q: Because TR1 modifies existing headers, can it negatively affect me when I'm not using it?

 

A: It shouldn't (if it does, that's a bug, and we really want to hear about it). You shouldn't see any broken behavior at runtime, nor any new compiler warnings or errors (at least under /W4, the highest level that we aim to keep the VC Libraries clean under). Of course, TR1 can slow down your build slightly (more code means more compilation time), and if you are very close to the /Zm limit for PCHs, the additional code can put you over the limit. You can define _HAS_TR1 to 0 project-wide in order to get rid of the new code.

 

Q: Does this patch affect the compiler or IDE?

 

A: No.

 

Q: Did you license Dinkumware's TR1 implementation?

 

A: Yes (see http://dinkumware.com/tr1.aspx ), just as we licensed their Standard Library implementation. So, you can expect the usual high level of quality.

 

Q: So, what has MS been doing?

 

A: Roughly speaking, additional testing and "MS-specific" stuff.

 

1. We've integrated TR1 into VC9, so TR1 lives right next to the STL. (This involved unglamorous work with our build system, to get the TR1 separately compiled components picked up into msvcp90.dll and friends, and with our setup technologies, to get the new headers and sources picked up into the Visual Studio installer.) As a result, users don't have to modify their include paths, or distribute new DLLs with their applications - they just need to apply the patch and update their CRT.

 

2. We've made TR1 play nice with /clr and /clr:pure (which are outside the domain of Standard C++, but which we must support, of course). At first, these switches caused all sorts of compiler errors and warnings. For example, even something as simple as calling a varargs function internally triggered a "native code generation" warning. These errors and warnings took a long time to iron out.

 

3. We're ensuring that TR1 compiles warning-free at /W4, in all supported scenarios. This includes switches like /Za, /Gz, and the like.

 

4. We're ensuring that TR1 is /analyze-clean.

 

As usual, we've preferred real fixes to workarounds to disabling warnings (and when we disable warnings, we do so only in the headers, not affecting user code).

 

5. We're identifying bugs in TR1 and working with Dinkumware to fix them. Dinkumware's code was very solid to begin with - but as ever, more eyes find more bugs. I've even found a couple of bugs in the TR1 spec itself (see http://open-std.org/JTC1/sc22/WG21/docs/lwg-active.html#726 and Issue 727 below).

 

6. We're striving for performance parity with Boost (which serves as a convenient reference; we could compare against GCC's TR1 implementation, but then we'd have to deal with the difference in compilers). In some areas, we won't get there for VC9 TR1 (hopefully, we should for VC10), but we've already made good progress. Thanks to MS's performance testing (which Rob Huyett has been in charge of), we identified a performance problem in regex matching, which Dinkumware has sped up by 4-5x. (Note that this fix didn't make it into the beta, which is roughly 18x slower at matching; current builds are roughly 3.8x slower.) And we've achieved performance parity for function (again, this fix didn't make it into the beta).

 

("Okay," you say, "but will regex::optimize make it faster?" Unfortunately, no. The NFA => DFA transformation suggested by regex::optimize will not be implemented in VC9 TR1, but we will consider it for VC10. In my one cursory test, regex::optimize did nothing with Boost 1.34.1.)

 

7. We're identifying select C++0x features to backport into TR1 - for example, allocator support for shared_ptr and function. While not in TR1, this is important to many customers (including our own compiler). This just got checked in, and isn't in the beta.

 

8. We're implementing IDE debugger visualizers for TR1 types. Like the STL (more so, in some cases), the representations of TR1 types are complicated, so visualizers really help with debugging. I've written visualizers for almost every TR1 type (I am secretly proud of how shared_ptr's visualizer switches between "1 strong ref" and "2 strong refs"). Note that the beta doesn't include any TR1 visualizers.

 

9. We've worked with Dinkumware to fix a small number of bugs present in VC8 SP1 and VC9 RTM ("because we were in the neighborhood"). One which was actually related to TR1 was that stdext::hash_set/etc. had an O(N), throwing, iterator-invalidating swap() (discovered because unordered_set/etc. shares much of its implementation). This has been fixed to be O(1), nofail, non-iterator-invalidating.

 

10. Because TR1 lives alongside the STL, we've made them talk to each other in order to improve performance. For example, STL containers of TR1 types (e.g. vector<shared_ptr<T> >, vector<unordered_set<T> >) will avoid copying their elements, just as STL containers of STL containers in VC8 and VC9 avoid copying their elements.

 

This is a little-known feature of the VC8 STL; it's there in the source for everyone to see, except that almost no one reads the Standard Library implementation (nor should they have a reason to).  Basically, this is a library implementation of C++0x "move semantics", although it's naturally much more limited than language support will be.  In VC8, template magic is used to annotate containers (vector, deque, list, etc.) as having O(1) swaps, so containers-of-containers will swap them instead of making new copies and destroying the originals.  (For builtin types, swapping would be less efficient.)

 

We've simply extended this machinery to the new types in TR1. Everything in TR1 with custom swap() implementations will benefit: shared_ptr/weak_ptr (avoiding reference count twiddling), function (avoiding dynamic memory allocation/deallocation), regex (avoiding copying entire finite state machines), match_results (avoiding copying vectors), unordered_set/etc. (avoiding copying their guts), and array (which doesn't have an O(1) swap(), but does call swap_ranges() - so arrays of things with O(1) swaps will benefit).

 

That is to say: if a vector<shared_ptr<T> > undergoes reallocation, the reference counts won't be incremented and decremented. That's really neat, if you ask me.

 

If you have any questions about or issues with the Feature Pack Beta, let us know!

 

Thanks,

 

Stephan T. Lavavej, Visual C++ Libraries Developer

  • [Pavel Minaev]

    Aha - it's good to know that memmove_s(), memmove(), and memcpy() are basically indistinguishable, and the same for fill() and memset().

    Thanks for the test case - profiling indicates that the vector test spends 76% of its time in vector<T>::_Construct_n(). I'll file a bug.

    > <cstdint> is by far the most important of all TR1 compat headers,

    > and also the simplest; why not have it and forgo the rest?

    The "which parts of TR1 should we ship" decision was made at the coarsest-grained level of Boost/C99/Math.

    [Phaeron]

    > I'm disappointed at stdint/cstdint being missing, too.

    There's always boost/cstdint.hpp.

    > I hate typing unsigned __int64 in one-off programs

    VC accepts "unsigned long long".

    > and I've never seen a major project that didn't have to have

    > its own typedefs for sized types. Lots of fun when they collide.

    Namespaces!

    Also - I'd like to personally thank you, Phaeron, for writing those two posts about autoexp.dat visualizers. They really helped me when I was writing the TR1 visualizers (which, as you will see, are extensively commented - unlike the existing STL visualizers).

    [Pavel Minaev]

    > At least I'm not aware of any still-relevant compiler for which this doesn't hold

    "ILP64" platforms make int, long, long long, and void * all 64 bits. I'm not sure which platforms actually implement ILP64.

    Stephan T. Lavavej

    Visual C++ Libraries Developer

  • > There's always boost/cstdint.hpp.

    I tend to compile lots of little test programs with cl.exe for which bringing in Boost is, um, a bit much.

    > VC accepts "unsigned long long".

    That's even longer!

    > Also - I'd like to personally thank you, Phaeron, for writing those two posts about

    > autoexp.dat visualizers. They really helped me when I was writing the TR1 visualizers

    > (which, as you will see, are extensively commented - unlike the existing STL

    > visualizers).

    You're welcome. You can probably imagine my amusement, though, that a developer on the VC++ Libraries team used reverse-engineered docs from an external source for the VC++ debugger. Go bug the debugger team and ask them to write better docs! Then tell them to release them to us. :)

  • > I've written visualizers for almost every TR1 type (I am secretly proud of how shared_ptr's visualizer switches between "1 strong ref" and "2 strong refs").

    How about boost::function? ;)

  • [Phaeron]

    > I tend to compile lots of little test programs with cl.exe for which bringing in Boost is, um, a bit much.

    At home, I drop Boost into VC\PlatformSDK\Include and VC\PlatformSDK\Lib, so I can use it without any /I switches.  (I could also have used VC\include and VC\lib .)  This is, of course, entirely unsupported - as a general rule you shouldn't perform brain surgery in Program Files - but it works entirely well.

    >> VC accepts "unsigned long long".

    > That's even longer!

    The typedefs I use at home are uc_t, us_t, ul_t, and ull_t. :-)

    > You're welcome. You can probably imagine my amusement, though,

    > that a developer on the VC++ Libraries team used reverse-engineered

    > docs from an external source for the VC++ debugger.

    The sad thing is that - to my knowledge - your docs are the most complete ones in existence. We don't have *any* internal docs for the visualizer, beyond the comments in autoexp.dat.

    [Pavel Minaev]

    > How about boost::function? ;)

    I visualize tr1::function too; however, pointers-to-bases are a "brick wall" to visualizers, so I can only preview them with "empty" or "full". Vaguely speaking, _Impl->_Callee._Object stores the functor, but there's no way to get that into the preview.

    For the same reason, shared_ptr deleters are not visualizable. When this happens, I provide [actual members] so you can dig into the representation; the foo,! trick isn't widely known, and is less convenient anyways.

    Yesterday, I checked in an enhanced regex visualizer. While basic_regex looks like it stores a plain string, it actually stores a finite state machine, which is completely un-visualizable. So, I added a data member named _Visualization to basic_regex that stores the string from which it was constructed, which we can use to preview the regex. By default, this is enabled in debug and disabled in ship (we'll fall back to a significantly less useful preview), although you can override this by defining _ENHANCED_REGEX_VISUALIZER (0 in debug would remove the overhead of storing the string; 1 in ship would make debugging easier). While basic_regex is much more heavyweight than a simple string, I didn't want to make ship any slower without people asking for it.

    Hopefully, you will be pleasantly surprised by the number of TR1 types that I visualize, and the comprehensiveness of their visualizers. weak_ptrs can be previewed with "expired", regex_iterators and regex_token_iterators have useful previews and children, and even the return value of bind() will be visualized (this hasn't been checked in yet, pending a bind() fix, but STL functors like plus<T>() and the like will also get visualizers, since that makes bind() visualizers much prettier).

    Stephan T. Lavavej

    Visual C++ Libraries Developer

  • I am also disappointed to not see stdint.  Having to make typedefs in portable code gets old quick.

    stdint and inttypes are both very simple, is there no way for them to be included?

  • Agreed. cstdint is necessary, not to mention ridiculously easy to implement. There's no excuse not to ship a standard header file which consists of nothing but a small set of extremely useful typedefs.

  • Since we are talking about Visualizers, does anyone else have this problem - on Vista w/ VC2005 SP1 (w/ vista update), no [Visualizer]s seem to work at all.

    My [AutoExpands] work properly, but I cannot even get STL container of ints to visualize as you would expect (e.g. I get {_Myfirst=0x003d4ea0 _Mylast=0x003d4eb4 _Myend=0x003d4eb8 } instead of {[2](x,y)}.

  • Btw, this is on Visual Studio 2005 Standard, though I can't see why that would make a difference.

  • > I visualize tr1::function too; however, pointers-to-bases are a "brick wall" to visualizers, so I can only preview them with "empty" or "full". Vaguely speaking, _Impl->_Callee._Object stores the functor, but there's no way to get that into the preview.

    Not quite. You can get past a pointer-to-base with a cast if you know what's really there. And you can use the same trick you did for regex - storing a member identifying the actual type of the functor inside tr1::function for debug builds, at least for some commonly-used functor types (e.g. plain function pointers and bind expressions).

  • [Cory Nelson]

    > I am also disappointed to not see stdint.

    I'd like to have cstdint in VC9 TR1 too, but remember the opportunity cost.

    If we had an extra day, week, or month to work on TR1, I'd want us and Dinkumware to look at regex perf.

    [mochi]

    > on Vista w/ VC2005 SP1 (w/ vista update), no [Visualizer]s seem to work at all.

    On my dev box (Server 2003 SP2 with VC8 SP1 Team Suite), visualizers work intermittently, which mystifies me. I had installed and uninstalled another edition of VC8 before, but hadn't done anything else unusual to that computer. (I'm 90% sure that my ordinary development work doesn't interact with the regular installation.) I really ought to nuke and pave that machine, but I'm waiting to get a quad-core.

    [Pavel Minaev]

    > Not quite. You can get past a pointer-to-base with a cast if you know what's really there.

    > And you can use the same trick you did for regex - storing a member identifying the actual

    > type of the functor inside tr1::function for debug builds, at least for some commonly-used

    > functor types (e.g. plain function pointers and bind expressions).

    Function pointers, okay - given a tr1::function<FT>, if it holds a function pointer, that's of type FT *. That's a good idea. But bind expressions, no - the type of a bind expression is highly variable, depending on more than its signature.

    regex's representation was almost completely opaque (except for the flags with which it was constructed), so the enhanced regex visualizer is rather valuable. I could imagine it being hard to track down the string from which a regex was constructed (especially in the case of constructing a regex from input iterators), even though the usual case is to have a const regex constructed from a string literal. tr1::function's representation, on the other hand, is obnoxious to pick through the first time, but does contain all of the information you want. So the need for an enhanced visualizer is less (although it sure would be convenient).

    I'll take a look at how simple it would be to add a "stores a function pointer" bool to tr1::function, although I suspect that it would require adding some overloads. Anything that could destabilize the implementation would be Bad. (regex's _Visualization didn't need any new overloads, so there was no danger of breaking something else. At worst, we'd forget to update the _Visualization when we should.)

    Thanks,

    Stephan T. Lavavej, Visual C++ Libraries Developer

  • Visual C++ Team Blog : MFC Beta Now Available Download details VC++ 2008 Libraries Feature Pack Beta

  • Visual C++ Team Blog : MFC Beta Now Available Download details VC++ 2008 Libraries Feature Pack Beta

  • Can we use MFC/TR1 for native/win32 programming and not MFC?

  • [Dave]

    > Can we use MFC/TR1 for native/win32 programming and not MFC?

    I don't understand your question, can you clarify it?

    Stephan T. Lavavej, Visual C++ Libraries Developer

  • Hey - everyone who says Microsoft needs to provide stdint.h. There's a public domain version available (from the MinGW toolset):

    http://www.cs.colorado.edu/~main/cs1300/include/stdint.h

    It required some tweaks for my use (to make the 64-bit stuff work with VC6 - I don't remember if changes were needed for any other MS compiler version).  I know that MS should provide this with the compiler (and I sure have no idea why they don't), but until they decide to you can have your portability in this small area with little in the way of maintainability headaches since it's not interdependent on other bits of the library - it's just a bunch of typedefs and macros.

Page 2 of 6 (82 items) 12345»