Welcome to MSDN Blogs Sign in | Join | Help

TR1 Fixes In VC9 SP1

STL enjoys speaking in the third person and also enjoys bringing you this exclusive news:

 

Visual Studio 2008 Service Pack 1 (VC9 SP1) contains the TR1 and MFC library extensions that were originally released in the Visual C++ 2008 Feature Pack Refresh.  But wait!  VC9 SP1 also contains many delicious fixes for TR1 and MFC.  (For TR1, "many" is 16; for MFC, "many" is 60 or more!)

 

As the current maintainer of the C++ Standard Library and TR1 implementations within Microsoft, STL has compiled an exhaustive list of the TR1 fixes in VC9 SP1.  But first!  Shout-outs must be sent to P.J. Plauger and Christopher J. Walker of Dinkumware, who tirelessly worked to implement most of these fixes, and Microsoft's compiler front-end ninja Jonathan Caves, who fixed nasty compiler bugs that were exposed by TR1.

 

 

The three most significant fixes are:

 

* A massive performance improvement in regex matching.

 

* An across-the-board performance improvement in STL containers of TR1 objects (e.g. vector<shared_ptr<T> >).

 

* A fix allowing tr1::function to store function objects with non-const function call operators.

 

 

This is the exhaustive list:

 

1. The STL algorithm search_n() no longer spuriously triggers _HAS_ITERATOR_DEBUGGING assertions.  (search_n() isn't part of TR1, but this is why it's being mentioned here:  A severe search_n() bug, a regression from VC8 SP1 to VC9 RTM where the predicate version attempted to use operator==(), was fixed in the VC9 Feature Pack Refresh.  However, the fix contained this less severe flaw, which was noticed in time to be truly fixed in VC9 SP1.)

 

2. The random distribution uniform_int<unsigned long long> no longer infinitely loops.

 

3. The <random> header has been overhauled, incorporating many C++0x improvements.

 

4. The copy constructors of the pseudorandom number generators now behave correctly.  (This was a subtle mistake where a template constructor provided a better match than a copy constructor during overload resolution.)

 

5. enable_shared_from_this's copy constructor and copy assignment operator have been corrected.  (This affected classes deriving from enable_shared_from_this, and did not affect other uses of shared_ptr.)

 

6. shared_ptr<const T> can now be constructed from const T *.  (This is relatively unusual.)

 

7. tr1::function can now store function objects with non-const function call operators.  (This was a severe problem.)

 

8. The performance of regex matching has been massively improved.  (In general, TR1 Regex is as fast or faster than Boost.Regex 1.35.0.  TR1 Regex is still slower than Boost for some regexes, such as those dominated by alternations like "cute|fluffy|kittens", but their performance has also improved significantly compared to the Feature Pack Refresh.  Further performance improvements are being investigated for VC10.)

 

9. The performance of unordered_set (etc.) and hash_set (etc.) has been significantly improved.  (tr1::unordered_set and stdext::hash_set share the same implementation.  erase() still presents performance problems, which are being investigated for VC10.)

 

10. result_of now accepts references to functions.

 

11. is_function and is_member_function_pointer now work correctly with variadic arguments.

 

12. is_polymorphic now works correctly.  (It previously gave bogus answers for classes like std::iostream.  This was a compiler bug fixed by Jonathan Caves.)

 

13. The <memory> header's declarations of the _InterlockedIncrement (etc.) intrinsics can now be suppressed by defining _DO_NOT_DECLARE_INTERLOCKED_INTRINSICS_IN_MEMORY .  This is for compatibility with <intrin.h> and <winbase.h>, which contain conflicting declarations for certain configurations of certain platforms.  (This workaround has been eliminated in VC10, which contains a comprehensive fix.)

 

14. mem_fn() now works with abstract base classes.  (This surprising bug was caused by library and compiler bugs, both fixed.  Other code may benefit from this compiler fix.)

 

15. is_pod and has_trivial_constructor now work correctly.  (They previously gave bogus answers for certain uncommon classes.)

 

16. The Swaptimization (previously mentioned in this VCBlog post) is now actually used for TR1 objects.

 

 

#16 deserves some explanation.

 

STL containers (vector, deque, list, set, multiset, map, multimap) are "fast-swappable"; x.swap(y) and swap(x, y) are constant-time, nofail, non-iterator-invalidating.  (You might remember that VC8's Swap Bug broke that last, very important part.)  std::string swap() is also constant-time and nofail, although it can invalidate iterators due to the small string optimization.

 

Constant-time means that swapping STL containers is implemented by swapping their guts (their pointers, whether to a vector's block of memory, a list's doubly-linked nodes, or a map's binary tree nodes).  That's far superior to all of the element-copying that "Container temp = a; a = b; b = temp;" would involve.

 

Now, when a vector undergoes reallocation, it has to copy its current elements from the old memory block to the new memory block.  When you have a vector of STL containers (vector<vector<int> >, vector<set<int> >, etc.), that would be slow, copying the sub-containers and doing lots of dynamic memory allocation and deallocation.

 

The Swaptimization, which was present in VC8 (possibly earlier, but STL hasn't checked), is a bit of template magic whereby STL containers are marked as having fast swaps.  When a vector<T> undergoes reallocation, it detects whether the T has a fast swap, and if so, will swap elements from the old memory block to the new memory block.  This is super fast!  (Why doesn't it always swap?  For vector<int>, simply copying ints from the old memory block to the new memory block is faster - nothing needs to be swapped back into the old memory block.)

 

Many TR1 objects, such as unordered_set and match_results and shared_ptr, also have fast swaps.  This is because they're either containers (like unordered_set) or they wrap containers (like match_results), or they're not containers but they have the same pointers-to-stuff structure (like shared_ptr).  So, Dinkumware and STL worked really hard to give all TR1 objects fast swaps, and mark them appropriately to be picked up by the Swaptimization.

 

Unfortunately, this was simply broken in the Feature Pack Refresh!  The problem was subtle.  The STL provides the swap() free function in namespace std, which performs the three-step dance that works for anything copyable and assignable (but might be slow).  The idea is that users with fast-swappable classes, in addition to providing member swap(), can fully specialize swap() in namespace std for their classes.  (Generally, users *aren't* supposed to add anything to namespace std.  However, Standard templates may be fully or partially specialized for user classes; this is paragraph 17.4.3.1/1 of the Standard.)  This works well enough.

 

However, users with fast-swappable class *templates* have to do something different.  A not-commonly-understood fact about C++ is that there are no such things as partial specializations of function templates.  Anything that looks like a partial specialization is actually an overload.  (Only classes can be partially specialized.)  In practice, overloads behave similarly enough to how users think partial specializations of function templates would work, and everyone gets along happily.

 

But this means that you can't add overloads of swap() to namespace std, even if you think they look like those mythical partial specializations.  So, if you have a fast-swappable class template, you need to provide a swap() free function in the same namespace as your class template, to be found through Argument-Dependent Lookup (ADL, formerly and less descriptively called Koenig Lookup).

 

(No, this isn't really ideal.  Swapping is such a fundamental operation that it really ought to be recognized in the Core Language like copying - but it's far too late to change that.)

 

So, TR1, which is almost but not quite part of the Standard, came along and provided a bunch of fast-swappable stuff in namespace std::tr1, and defined overloads of swap(), again within std::tr1.  The TR1 classes were fast-swappable, annotated as such, and detected as such by the existing Swaptimization machinery within vector and a few other places.  So why didn't it work?

 

It turned out that the Swaptimization was being performed with a call to qualified std::swap().  Most people don't do C++ name lookup in their heads for fun, but the important thing to know is this: Qualified Name Lookup disables ADL.  Uh oh!  So, the general implementation of std::swap() (doing the slow three-step dance of copying) was chosen, instead of the specific implementations of std::tr1::swap() for shared_ptr<T>, unordered_set<T>, and so forth.  Disaster.  STL was deeply mortified.

 

(Why was a qualified call being used?  Another name lookup subtlety - unqualified calls like swap() activate both Unqualified Name Lookup (the usual, which everyone is familiar with) and ADL (which everyone really should be familiar with).  Ordinarily, the union of the sets of functions they find is then used for overload resolution (picking what actually gets called).  But if Unqualified Name Lookup finds a member function, ADL is bypassed; this is paragraph 3.4.2/2a of the Standard.  So, within a class that defines a member swap(), calling unqualified swap() doesn't activate ADL, nor does it even find std::swap() - it finds the member swap().  Thus, qualified calls became conventional within VC's Standard Library implementation.)

 

The fix was to define a wrapper, std::_Swap_adl(), that calls unqualified swap(), activating ADL properly.  The STL now calls std::_Swap_adl() whenever ADL is desired.  (It continues to call std::swap() whenever ADL is unnecessary, such as when swapping builtins).  As with all _Leading_underscore_capital names, users shouldn't call std::_Swap_adl() themselves (it may change or disappear in future versions).  You can perform the exact same trick by defining your own wrapper in your own namespace of choice, with the wrapper containing a "using namespace std;" and an unqualified call to swap().  (If you look at std::_Swap_adl()'s implementation, it lacks a using-directive - it already lives in namespace std, unlike anything you can define.)

 

The end result is that when a vector<shared_ptr<T> > undergoes reallocation, absolutely no reference counts are incremented or decremented - which is a significant performance win.  Woot!

 

Note that none of these fixes were in the SP1 Beta, which branched for release as the Feature Pack was being finished.

 

Stephan T. Lavavej

Visual C++ Libraries Developer

 

Published Monday, August 11, 2008 12:32 PM by vcblog

Comments

Monday, August 11, 2008 3:53 PM by TR1 Fixes In VC9 SP1 | Easycoded

# TR1 Fixes In VC9 SP1 | Easycoded

Monday, August 11, 2008 4:00 PM by Adam C Merz

# re: TR1 Fixes In VC9 SP1

Out of curiousity, was any performance testing of tr1::regex done comparing to boost::xpressive rather than boost::regex? Given the introduction of boost::xpressive, boost::regex strikes me as a legacy library, only useful for a mostly-TR1-compatible API.

Monday, August 11, 2008 5:29 PM by Stephan T. Lavavej [MSFT]

# re: TR1 Fixes In VC9 SP1

Remember that <regex> is part of the C++0x Standard Library, so I'd hardly call it "legacy".

I wasn't familiar with Boost.Xpressive, although from glancing at its documentation it appears to be extremely powerful. I'll look at it for future performance comparisons, thanks.

Monday, August 11, 2008 6:05 PM by someone

# STL/CLR fixed?

STL/CLR is embarrassingly slow compared to BCL. Has this been addressed?

Tuesday, August 12, 2008 1:21 AM by int19h

# re: TR1 Fixes In VC9 SP1

All good stuff. I wish the trait framework used to mark classes for swap optimization was public and documented, though, so we could use it for our own (unportable, obviously - though nothing an #ifdef can't alleviate - but sometimes performance is more important).

Tuesday, August 12, 2008 3:17 AM by hito

# re: TR1 Fixes In VC9 SP1

SP1's unordered_set is horribly slow compare to boost::unordered_set or even std::set.

and worse, it's destructer is unbelievably slow.

but if i called clear() before destructer is called, it is not so slow.

Tuesday, August 12, 2008 9:39 AM by MR

# re: TR1 Fixes In VC9 SP1

Does anyone have a sense of how TR1 regex compares to the exiting ATL regex implementation (CAtlRegExp)? From a performance and or functional perspective?

Tuesday, August 12, 2008 10:10 AM by Visual Studio Hacks

# Visual Studio Links #64

My latest in a series of the weekly, or more often, summary of interesting links I come across related to Visual Studio. Yesterday, Visual Studio 2008 SP1 and .Net 3.5 SP1 were released. Below is a list of links related to those releases: Greg Duncan

Tuesday, August 12, 2008 12:01 PM by Richard Webb

# re: TR1 Fixes In VC9 SP1

Hi,

I've run the Boost regression tests with SP1 final and a lot of the TR1 failures i was seeing before have been fixed, but there are still a couple left.

For example, there is a problem with a missing result_type definition in Bind (http://tinyurl.com/5myz9f). You previously mentioned (http://blogs.msdn.com/vcblog/archive/2008/04/07/visual-c-2008-feature-pack-released.aspx#8405685) that this was a known bug, so did it not get fixed in SP1?

Thanks,

Richard Webb

Tuesday, August 12, 2008 12:40 PM by Adam C Merz

# re: TR1 Fixes In VC9 SP1

Re: boost::regex -- by "legacy" I mean, if you're using Boost, then presumably you want something better than what's in the standard; because <regex> is standard in C++0x/TR1, I'd call boost::regex legacy since it doesn't offer much beyond what the standard already has. boost::xpressive, on the other hand, does have quite an advantage over <regex> in terms of design and performance, especially in regards to static expressions.

Tuesday, August 12, 2008 1:20 PM by jmm

# re: TR1 Fixes In VC9 SP1

Your post lists the 16 fixes for TR1, but what about the 60 fixes for MFC?  Is there a post or article somewhere about these?

Tuesday, August 12, 2008 1:49 PM by jmm

# re: TR1 Fixes In VC9 SP1

I went to the official page for Microsoft Visual Studio 2008 Service Pack 1 (exe), which is: http://www.microsoft.com/downloads/details.aspx?FamilyId=FBEE1648-7106-44A7-9649-6D9F6D58056E&displaylang=en

At the bottom, within section [Related Resources], I clicked on:

2. Fixes included in this Service Packs (KB945140)

This gave me [Visual Studio 2008 Service Pack 1 Beta release notes and a list of fixed issues], which was published April 29, 2008.

Hopefully the actual fix list is posted sometime.  Info on the MFC fixes would be great too.

Tuesday, August 12, 2008 7:25 PM by Pat Brenner

# re: TR1 Fixes In VC9 SP1

Hi all,

I've just posted a summary of the bugs that we fixed in MFC for VS2008 SP1.  See it here: http://blogs.msdn.com/vcblog/archive/2008/08/12/bugs-fixed-in-mfc-in-visual-studio-2008-sp1.aspx

Pat Brenner

Visual C++ Libraries Development

Tuesday, August 12, 2008 7:54 PM by Stephan T. Lavavej [MSFT]

# re: TR1 Fixes In VC9 SP1

[int19h]

> I wish the trait framework used to mark classes for swap optimization

> was public and documented, though, so we could use it for our own

> (unportable, obviously - though nothing an #ifdef can't alleviate - but

> sometimes performance is more important).

This is probably as documented as it'll get.  See below for my utterly unsupported example.

[hito]

> SP1's unordered_set is horribly slow compare to boost::unordered_set or even std::set.

> and worse, it's destructer is unbelievably slow.

> but if i called clear() before destructer is called, it is not so slow.

Please file bugs with specific test cases through Microsoft Connect. We've identified one major performance problem in tr1::unordered_set; erase() doesn't achieve its required complexity.

(I thought Boost 1.35.0 hadn't implemented the unordered containers yet; see http://www.boost.org/doc/libs/1_35_0/doc/html/boost_tr1.html .)

[MR]

> Does anyone have a sense of how TR1 regex compares to the exiting ATL regex implementation (CAtlRegExp)?

> From a performance and or functional perspective?

CAtlRegExp, along with the rest of ATL Server, was removed from VC9.

Hopefully, TR1 Regex outperforms CAtlRegExp, but we haven't done any performance comparisons there.  From a usability perspective, TR1 Regex wins hands down.

[Richard Webb]

> I've run the Boost regression tests with SP1 final and a lot of the TR1

> failures i was seeing before have been fixed, but there are still a couple left.

> For example, there is a problem with a missing result_type definition in Bind

> (http://tinyurl.com/5myz9f). You previously mentioned

> (http://blogs.msdn.com/vcblog/archive/2008/04/07/visual-c-2008-feature-pack-released.aspx#8405685)

> that this was a known bug, so did it not get fixed in SP1?

Correct; this was postponed to VC10.

And here's that example for int19h:

C:\Temp>type meow.cpp

#include <iostream>

#include <ostream>

#include <vector>

using namespace std;

namespace feline {

   struct kitty {

       kitty() { cout << "default ctor" << endl; }

       kitty(const kitty&) { cout << "copy ctor" << endl; }

       kitty& operator=(const kitty&) { cout << "assign" << endl; return *this; }

       ~kitty() { cout << "dtor" << endl; }

       void swap(kitty&) { cout << "swap" << endl; }

   };

   void swap(kitty& a, kitty& b) { a.swap(b); }

}

// Specific to VC9 SP1 and above.

// This machinery was broken for classes outside namespace std in VC9 RTM and below.

// This machinery will not be present in VC10 and above.

#if defined(_MSC_VER) && _MSC_VER == 1500 && _MSC_FULL_VER >= 150030729

   #include <xutility>

   namespace std {

       template <> class _Move_operation_category<feline::kitty> {

       public:

           typedef _Swap_move_tag _Move_cat;

       };

   }

#endif

int main() {

   vector<feline::kitty> v;

   cout << "*** Constructing cat." << endl;

   feline::kitty cat;

   cout << "*** Pushing back cat #1." << endl;

   v.push_back(cat);

   cout << "*** Pushing back cat #2." << endl;

   v.push_back(cat);

   cout << "*** Destroying cat and v." << endl;

}

C:\Temp>cl /EHsc /nologo /W4 meow.cpp

meow.cpp

C:\Temp>meow

*** Constructing cat.

default ctor

*** Pushing back cat #1.

copy ctor

default ctor

dtor

default ctor

dtor

*** Pushing back cat #2.

copy ctor

default ctor

copy ctor

swap

dtor

default ctor

dtor

dtor

*** Destroying cat and v.

dtor

dtor

dtor

Note that the Swaptimization requires a default ctor.

Wednesday, August 13, 2008 5:49 AM by int19h

# re: TR1 Fixes In VC9 SP1

Thank you.

Hopefully, VC10 will see C++0x finalized and implemented, with its move constructors and all, so we won't need this hack by that time.

Wednesday, August 13, 2008 1:16 PM by Richard Webb

# re: TR1 Fixes In VC9 SP1

>>>>>>>>>>>>>>>

(I thought Boost 1.35.0 hadn't implemented the unordered containers yet; see http://www.boost.org/doc/libs/1_35_0/doc/html/boost_tr1.html .)

>>>>>>>>>>>>>>>

It didn't - they're new in 1.36, due any day now.

See http://beta.boost.org/users/news/version_1_36_0

Thursday, August 14, 2008 2:08 AM by KluYa

# re: TR1 Fixes In VC9 SP1

I see a lot of things are being remanded to VC10. Is there any timeframe on when VC10 will hit? Late 2009, early 2010?

Thursday, August 14, 2008 4:41 PM by Stephan T. Lavavej [MSFT]

# re: TR1 Fixes In VC9 SP1

[KluYa]

> I see a lot of things are being remanded to VC10.

I'd say "some", not "a lot", except wrt <functional> and especially bind(). Only one bugfix was deliberately kept out of VC9 SP1 (this was the fairly extensive fix for the <memory> _InterlockedFoo problem, which was too risky for a service pack).

> Is there any timeframe on when VC10 will hit?

We're not talking about that yet.

Stephan T. Lavavej, Visual C++ Libraries Developer

Friday, August 15, 2008 4:39 PM by mikeb

# re: TR1 Fixes In VC9 SP1

You said: "So, within a class that defines a member swap(), calling unqualified swap() doesn't activate ADL, nor does it even find std::swap() - it finds the member swap()"

Does that mean the Scott Meyers' Item 25 in Effective C++ 3rd Ed. should be amended so that:

- in a class that has a member swap(), instead of having a "using std::swap" declaration and directly calling an unqualified swap()

it should:

- call a wrapper non-member template function that has a "using std::swap" declaration and calls an unqualified swap() - ie., our own implementation of std::_Swap_adl() that's not in the std namespace and doesn't start with an '_'?

It sounds like to be safe we should always call this non-member wrapper template function instead of calling swap(T&, T&) directly.

Jeez - this name lookup stuff is so convoluted, I'm not even sure if this question makes any sense.

Friday, August 15, 2008 5:25 PM by grokbrsm

# VC9 SP1: problems with tr1::function?

The following code breaks with an access violation when executing line

  (*i)(tmp);

after an update to VC9 SP1. It works fine with RTM and even SP1 beta. Verified on two different machines, one (win XP x64) that had the beta, the other that didn't (win XP 32 bits).

---------------------

#include <iostream>

#include <vector>

#include <functional>

struct my_class

{

 void f() { std::cout << "my_class::f()" << std::endl; }

};

void g(my_class x)

{

 std::cout << "g(my_class)" << std::endl;

}

struct h

{

 void operator()(my_class) const {

   std::cout << "h::operator()(my_class)" << std::endl;

 }

};

int main()

{

 typedef std::tr1::function<void(my_class)> F;

 std::vector<F> ops;

 ops.push_back(&my_class::f);

 ops.push_back(&g);

 ops.push_back(h());

my_class tmp;

 for (std::vector<F>::iterator i = ops.begin(); i != ops.end(); i++)

 {

   (*i)(tmp);

 }

}

-------------------------

Friday, August 15, 2008 5:38 PM by Stephan T. Lavavej [MSFT]

# re: TR1 Fixes In VC9 SP1

> It sounds like to be safe we should always call this non-member wrapper template function instead of calling swap(T&, T&) directly.

According to my understanding, yes.

(Also according to my understanding, accidentally getting member swap is not particularly dangerous, as member swap will be one-arg while free swap is two-arg.  It's accidentally getting general swap that's dangerous, as it'll compile but run slowly.)

I believe that Boost has their own swap wrapper for precisely this purpose.

Friday, August 15, 2008 6:23 PM by Stephan T. Lavavej [MSFT]

# re: TR1 Fixes In VC9 SP1

[grokbrsm]

> VC9 SP1: problems with tr1::function?

A bazillion thanks for the bug report!

I've confirmed this. The underlying problem is that when we implemented the Small Functor Optimization, tr1::function::swap() wasn't updated accordingly. This was broken in the Feature Pack, and no one noticed. But now that the Swaptimization works for vector<function<FT> >, that's broken too. Profoundly awful, as vector-of-function is so powerful.

I'll file a bug and get this fixed in VC10.

Saturday, August 16, 2008 2:09 AM by grokbrsm

# re: TR1 Fixes In VC9 SP1

Well the SP1 problems with std::vector of tr1::function render tr1 almost useless as far as I am concerned, which is a shame since the integration of tr1 containers in the debugger is something I would not want to lose (therefore I would not like to use boost instead of the MSVC impl)... Is it possible to fix or work around the problem through a small modification of tr1 headers? If I understand correctly, all the tr1::function is implemented in headers.

Saturday, August 16, 2008 12:08 PM by grokbrsm

# re: TR1 Fixes In VC9 SP1

Well, I found a fix for the std::vector of tr1::function issue. in xxfunction, replace

void _Swap(_Myt& _Right)

{

(...)

}

by

void _Swap(_Myt& _Right)

{ // swap contents with contents of _Right

bool _right_is_local = (void *)_Right._Impl == (void *)&_Right._Space;

bool _this_is_local = (void *)_Impl == (void *)&_Space;

if (_right_is_local || _this_is_local)

{

_STD swap(_Space, _Right._Space);

}

_Ptrt *_Timpl = _Right._Impl;

_Right._Impl = _this_is_local?((_Ptrt *)&_Right._Space):_Impl;

_Impl = _right_is_local?((_Ptrt *)&_Space):_Timpl;

}

I'd be glad to know if this really works as expected in every situation.  

Monday, August 18, 2008 3:11 PM by Stephan T. Lavavej [MSFT]

# re: TR1 Fixes In VC9 SP1

grokbrsm:

> I'd be glad to know if this really works as expected in every situation.

It doesn't. (A functor can own an object which has a pointer back to the functor.)

We strongly advise against header-hacking, as it has the potential to make your Visual Studio installation unpatchable.

There are a few things that you can do:

1. Use boost::function.  It's not like tr1::function has a useful visualizer anyways.  (I wrote all of the TR1 visualizers, and they are as detailed as possible; unfortunately, the visualizer machinery can't see through a pointer-to-base, which is what powers tr1::function, so it's visualized with either "empty" or "full".)

2. Write a wrapper:

C:\Temp>type meow.cpp

#include <functional>

#include <iostream>

#include <ostream>

#include <vector>

template <typename FT> struct fxn {

   fxn() : m_f() { }

   fxn(int) : m_f() { }

   template <typename F> fxn(F f) : m_f(f) { }

   fxn(const fxn& other) : m_f(other.m_f) { }

   fxn& operator=(int) {

       m_f = 0;

       return *this;

   }

   template <typename F> fxn& operator=(F f) {

       m_f = f;

       return *this;

   }

   fxn& operator=(const fxn& other) {

       m_f = other.m_f;

       return *this;

   }

   std::tr1::function<FT> m_f;

};

int add(int x, int y) {

   return x + y;

}

int mult(int x, int y, int z) {

   return x * y * z;

}

int main() {

   using namespace std;

   using namespace std::tr1;

   using namespace std::tr1::placeholders;

   vector<fxn<int (int, int)> > v;

   v.push_back(add);

   v.push_back(bind(mult, _1, _2, 10));

   v.push_back(minus<int>());

   for (vector<fxn<int (int, int)> >::const_iterator i = v.begin(); i != v.end(); ++i) {

       cout << i->m_f(3, 4) << endl;

   }

}

C:\Temp>cl /EHsc /nologo /W4 meow.cpp

meow.cpp

C:\Temp>meow

7

120

-1

(This wrapper attempts to look like tr1::function for the purposes of construction and assignment, but otherwise requires you to use m_f.)

3. Request a hotfix.

Monday, August 18, 2008 4:33 PM by grokbrsm

# re: TR1 Fixes In VC9 SP1

> It doesn't. (A functor can own an object which has a pointer back to the functor.)

Could you give a hint at when this can occur? If I understand correctly, in that case that pointer should be updated to point to the correct functor object, and obviously this does not happen with the code I posted.

The wrapper trick works because it prevents the "swaptimization"?

Thanks a lot for your detailed and insightful answers.

Monday, August 18, 2008 5:43 PM by Stephan T. Lavavej [MSFT]

# re: TR1 Fixes In VC9 SP1

> Could you give a hint at when this can occur?

That's just a pathological example that I thought up.

> If I understand correctly, in that case that

> pointer should be updated to point to the correct

> functor object, and obviously this does not happen

> with the code I posted.

The problem is that your code is performing a bitwise copy of the stored functor, which can mangle non-PODs. To be truly correct, function::swap() must copy construct and destroy the stored functor. I now have a fix that does exactly this.

> The wrapper trick works because it prevents

> the "swaptimization"?

Bingo.

Monday, August 18, 2008 7:22 PM by Michael Marcin

# re: TR1 Fixes In VC9 SP1

I have some legacy code that uses boost::shared_ptr in std containers.

Will I have to convert that to std::tr1::shared_ptr to get the vector realloc with no reference count manipulation or does it rely purely on adl and thus should work as is by choosing the boost::swap overload for shared_ptr?

Monday, August 18, 2008 8:07 PM by Stephan T. Lavavej [MSFT]

# re: TR1 Fixes In VC9 SP1

You'll either have to use tr1::shared_ptr, or partially specialize std::_Move_operation_category to annotate boost::shared_ptr as fast-swappable. There's no way to automatically detect fast-swappable types; they have to be annotated as such.

(If you partially specialize std::_Move_operation_category, you'll want to do so as early as possible. 14.7.3/7: "When writing a specialization, be careful about its location; or to make it compile will be such a trial as to kindle its self-immolation." If I were doing that, I'd forward-declare boost::shared_ptr and partially specialize std::_Move_operation_category at the top of my PCH, before anything else has a chance to instantiate vector<boost::shared_ptr<T> >.)

Tuesday, August 19, 2008 4:01 PM by Pierre B.

# re: TR1 Fixes In VC9 SP1

Wow! Very interesting. It's also very depressing that the chance of getting user-written template to work properly is very low. The amount of work-around needed to avoid all the gotchas of overloading, specialization, name lookup, makes it unlikely mere mortal can get it right.

Tuesday, August 19, 2008 4:21 PM by mikeb

# re: TR1 Fixes In VC9 SP1

"will be such a trial as to kindle its self-immolation."

Haha - I thought for sure that you were paraphrasing the standard for effect.  But I see that "self-immolation" even made it into the index twice - once for "self-immolation", and again for "immolation, self"!

Tuesday, August 19, 2008 4:54 PM by Kris

# re: TR1 Fixes In VC9 SP1

Great post. Last time I talked with you was in the nuwen IRC probably 5 years ago when you were about to leave to work on Outlook at MS. VC++ Library Developer? Nice.

Tuesday, August 19, 2008 5:16 PM by Stephan T. Lavavej [MSFT]

# re: TR1 Fixes In VC9 SP1

Pierre B.:

Actually, it's easy for users to use templates (including the Standard Library), and it's not terribly difficult to write templates with a moderate level of genericity.

What's difficult is implementing the Standard Library - the trick here was picking up user-defined swaps, which is an extreme level of customizability.

Note that the rules for getting your user-defined swaps to be picked up are easy: merely package them in the same namespace as your classes, which is the usual level of ADL cleanliness that you should be striving for (see Item 58 of C++ Coding Standards by Sutter and Alexandrescu for the full story).

mikeb:

Did you notice that it's a limerick? (I noticed the rhyming pattern when I first saw it, but didn't realize it was a limerick until someone else pointed it out to me.)

Kris:

Yup, I was an Outlook Search Dev in my former life, which I mentioned here: http://blogs.msdn.com/vcblog/archive/2007/02/26/stl-destructor-of-bugs.aspx

Wednesday, August 20, 2008 6:13 AM by int19h

# re: TR1 Fixes In VC9 SP1

> VC++ Library Developer? Nice.

Well, with the name like that (or rather, initials), it's probably just his karma. I can't help but smile (in a good way) every time I see stl@microsoft.com - that's one 'leet email address! ;)

Wednesday, August 20, 2008 2:09 PM by Michael Marcin

# re: TR1 Fixes In VC9 SP1

How can I detect that I'm building on VC9 with SP1 installed using the preprocessor?

I remember reading http://tinyurl.com/ys99kr which said that _MSC_BUILD would be used in the future to allow us to detect service pack versions but during this old blogging _MSC_BUILD for 2008 was 1 and it still is 1 for me with SP1 installed. I don't have a computer without SP1 installed to check against however.

Wednesday, August 20, 2008 4:11 PM by Stephan T. Lavavej [MSFT]

# re: TR1 Fixes In VC9 SP1

Michael Marcin:

_MSC_BUILD can be used to precisely identify the compiler version number, but it does not directly correspond to service pack level (i.e. it is NOT 0 for RTM, 1 for SP1, etc.).

To summarize JonCaves' explanation:

VC9 RTM's compiler version number was 15.00.21022.08. This is major.minor.build.minor-build. The major.minor version of 15.00 simply means "VC9". The build version of 21022 corresponds to the daily build that was selected to become RTM. (This was 10/22/2007's build.) The minor-build version of 08 means that this build was "respun" 8 times to fix last-minute bugs. (Every daily build begins with a minor-build version of 00. During development, we typically generate new daily builds instead of respinning a specific build, so the minor-build version remains at 00 and is actually elided from cl's output. But for betas and official releases, we respin specific builds to gold-plate the bits, and typically the minor-build version is greater than 00.)

_MSC_FULL_VER corresponds to major.minor.build, while _MSC_BUILD corresponds to minor-build (yes, the names are somewhat confusing - hence the blog post).

VC8, which lacked _MSC_BUILD, had an RTM version number of 14.00.50727.42 and an SP1 version number of 14.00.50727.762.  Therefore, their _MSC_FULL_VER values were identical, and they were indistinguishable without resorting to trickery.

We added _MSC_BUILD to prevent a recurrence of this.

Now, to explain what you saw:

VC9 Beta 2's version number was 15.00.20706.01.

VC9 RTM's version number was 15.00.21022.08.

VC9 SP1's version number is 15.00.30729.01.

By coincidence, we respun Beta 2 and SP1 exactly once. That's why their minor-build numbers are identical.

But unlike VC8, we increased SP1's build number (30729 indicates 7/29/2008's build). This is probably due to a change in our build process. So, _MSC_BUILD isn't actually needed to distinguish them.

Here's the fully correct way to identify VC9 SP1 or above:

C:\Temp>type meow.cpp

#include <iostream>

#include <ostream>

using namespace std;

int main() {

   cout << "_MSC_FULL_VER: " << _MSC_FULL_VER << endl;

   cout << "_MSC_BUILD: " << _MSC_BUILD << endl;

   #if defined(_MSC_VER) && (_MSC_FULL_VER > 150021022 || _MSC_FULL_VER == 150021022 && _MSC_BUILD >= 8)

       cout << "This is VC9 RTM or above." << endl;

   #endif

   #if defined(_MSC_VER) && (_MSC_FULL_VER > 150030729 || _MSC_FULL_VER == 150030729 && _MSC_BUILD >= 1)

       cout << "This is VC9 SP1 or above." << endl;

   #endif

}

C:\Temp>cl /EHsc /nologo /W4 meow.cpp

meow.cpp

With VC9 RTM:

C:\Temp>meow

_MSC_FULL_VER: 150021022

_MSC_BUILD: 8

This is VC9 RTM or above.

With VC9 SP1:

C:\Temp>meow

_MSC_FULL_VER: 150030729

_MSC_BUILD: 1

This is VC9 RTM or above.

This is VC9 SP1 or above.

The cout << "_MSC_BUILD: " << _MSC_BUILD << endl; line won't compile for VC8, but the #if tests will work correctly (without triggering warnings).

Wednesday, August 20, 2008 5:26 PM by Michael Marcin

# re: TR1 Fixes In VC9 SP1

Thank you for that detailed explanation.

Thursday, August 21, 2008 5:23 PM by Niels Dekker

# re: TR1 Fixes In VC9 SP1

Thanks for your information, Stephan!

You wrote:

> I believe that Boost has their own swap wrapper for precisely this purpose.

FYI, Boost's swap utility isn't yet officially released, but it's available at https://svn.boost.org/svn/boost/trunk/boost/utility/swap.hpp

See also https://svn.boost.org/svn/boost/trunk/libs/utility/swap.html

Saturday, August 23, 2008 6:56 AM by Niels Dekker

# How to tweak Swaptimization in a generic way?

Would it be okay to tweak this "Swaptimization" by defining the macro _DEFAULT_MOVE_OPERATION_CATEGORY in a different way than <xutility> does? It looks to me that in general, the penalty of copying, when swapping is preferable, is much higher than the penalty of swapping, when copying is preferable. So would it be okay to change the default, by adding the following command line argument to the compiler?  /D "_DEFAULT_MOVE_OPERATION_CATEGORY=_Swap_move_tag"

STL wrote: "There's no way to automatically detect fast-swappable types"

A type that has its own swap overload is usually fast-swappable. David Abrahams has actually just posted a has_swap_overload<T> metafunction at http://lists.boost.org/Archives/boost/2008/08/141334.php

Ideally, Swaptimization should be applied to type T by default, if-and-only-if T has its own swap overload. Right? Could a metafunction like has_swap_overload<T> be used to tweak Swaptimization in a more generic way?

Monday, August 25, 2008 6:46 AM by Alex

# TR1 for Windows Mobile projects

Windows Mobile projects in VC9 configured to use "ce\include" folder with different version of STL and without TR1 additions available in regular "include" folder.

Does this mean that TR1 one is not supported on Windows Mobile projects in VC9?

Monday, August 25, 2008 2:18 PM by Stephan T. Lavavej [MSFT]

# re: TR1 Fixes In VC9 SP1

[Niels Dekker]

> Would it be okay to tweak this "Swaptimization" by defining the macro _DEFAULT_MOVE_OPERATION_CATEGORY in a different way than <xutility> does?

No. That would break some code, and slow down some other code.

The Swaptimization requires a default constructor, but the STL does not. Activating the Swaptimization for all types would therefore break containers of types without default constructors.

Furthermore, swapping is slower than copying for PODs. Slowing down vector<unsigned char> is bad news indeed.

_DEFAULT_MOVE_OPERATION_CATEGORY shouldn't be a macro in the first place; it is not a point of customization.

> Ideally, Swaptimization should be applied to type T by default, if-and-only-if T has its own swap overload. Right?

According to my understanding, there is no way to detect explicit specializations of std::swap (as opposed to overloads in another namespace).

> Could a metafunction like has_swap_overload<T> be used to tweak Swaptimization in a more generic way?

This question is (happily) moot due to rvalue references.

[Alex]

> Windows Mobile projects in VC9 configured to use "ce\include" folder with different version of STL and without TR1 additions available in regular "include" folder.

> Does this mean that TR1 one is not supported on Windows Mobile projects in VC9?

CE's STL is maintained by an entirely different team, like the X360.

Wednesday, August 27, 2008 5:43 AM by Alex

# re: TR1 Fixes In VC9 SP1

> CE's STL is maintained by an entirely different team, like the X360.

Why? Compiler front end is the same. What's the problem?

Wednesday, August 27, 2008 4:49 PM by Niels Dekker

# re: TR1 Fixes In VC9 SP1

STL wrote: "The Swaptimization requires a default constructor, but the STL does not"

Thanks for reminding me! :-) Does VC 9 provide a way to estimate whether a type is default-constructible?

"Furthermore, swapping is slower than copying for PODs. Slowing down vector<unsigned char> is bad news indeed."

Okay. But now I may have found a bug in \VC\include\array. It has a _Move_operation_category<tr1::array<_Ty,_Size>> specialization, having "typedef _Swap_move_tag _Move_cat". Which activates Swaptimization for an array of PODs, right? I think that tr1::array<_Ty,_Size> should only be "swaptimized" whenever _Ty itself is "swaptimized". So _Move_operation_category<tr1::array<_Ty,_Size>> should have:

 typedef typename _Move_operation_category<_Ty>::_Move_cat _Move_cat;

Don't you think?  

"_DEFAULT_MOVE_OPERATION_CATEGORY shouldn't be a macro in the first place; it is not a point of customization."

Unfortunately. Anyway, in "STL-implementation independent code", it does at least provide a simple way to check if the STL supports  Swaptimization, by doing #ifdef _DEFAULT_MOVE_OPERATION_CATEGORY. (Right?) Which could be helpful to activate Swaptimization within  Boost, as we're discussing at "[boost] Enabling fast swap optimization for Boost types VC9 SP1.", http://thread.gmane.org/gmane.comp.lib.boost.devel/178944

Thanks again!

Wednesday, August 27, 2008 6:23 PM by Stephan T. Lavavej [MSFT]

# re: TR1 Fixes In VC9 SP1

[Niels Dekker]

> Does VC 9 provide a way to estimate whether a type is default-constructible?

TR1 doesn't contain such a type trait. (has_trivial_constructor and has_nothrow_constructor have been renamed to has_trivial_default_constructor and has_nothrow_default_constructor in C++0x, but there is no has_default_constructor.)

I don't know whether has_default_constructor can be implemented in plain C++.

> I think that tr1::array<_Ty,_Size> should only be "swaptimized" whenever _Ty itself is "swaptimized".

Correct. This was my oversight. That makes three instances of Swaptimization-related borkage so far (sigh). But at least vector<shared_ptr<T> > is fast!

> Anyway, in "STL-implementation independent code", it does at least provide

> a simple way to check if the STL supports  Swaptimization, by doing #ifdef

> _DEFAULT_MOVE_OPERATION_CATEGORY. (Right?)

Incorrect.  This macro existed in VC9 RTM (and VC8, IIRC), but the Swaptimization was fixed to work for types other than those directly within namespace std only in VC9 SP1.

> Which could be helpful to activate Swaptimization within Boost

As I posted above, here's how to do it:

// Specific to VC9 SP1 and above.

// This machinery was broken for classes outside namespace std in VC9 RTM and below.

// This machinery will not be present in VC10 and above.

#if defined(_MSC_VER) && _MSC_VER == 1500 && _MSC_FULL_VER >= 150030729

  #include <xutility>

  namespace std {

      template <> class _Move_operation_category<feline::kitty> {

      public:

          typedef _Swap_move_tag _Move_cat;

      };

  }

#endif

Thursday, August 28, 2008 2:28 AM by SvenC

# re: TR1 Fixes In VC9 SP1

Stephan, I was pretty sure that you are really good at what you do. And with your last statement you proved it again: you are so good that you have no problems to openly tell when you do not know something (the has_default_constructor question). I like that and feel that STL is in good hands for VC++! Thanks, SvenC

Thursday, August 28, 2008 3:37 PM by Niels Dekker

# re: TR1 Fixes In VC9 SP1

>> I think that tr1::array<_Ty,_Size> should only be "swaptimized" whenever _Ty itself is "swaptimized".

> Correct. This was my oversight.

Would it be helpful if I'd submit the tr1::array<_Ty,_Size> Swaptimization issue to Microsoft Connect?

Thursday, August 28, 2008 4:14 PM by Stephan T. Lavavej [MSFT]

# re: TR1 Fixes In VC9 SP1

SvenC: The more one works with C++, the more reluctant one becomes about saying "X can't be done in C++".  :-)

Niels Dekker: Not especially, as this machinery is being ripped out in VC10. I'll see if we can hotfix function::swap() and the pair/tuple/array annotations simultaneously.

Thursday, August 28, 2008 5:21 PM by Niels Dekker

# re: TR1 Fixes In VC9 SP1

> I'll see if we can hotfix function::swap() and the pair/tuple/array annotations simultaneously.

It's not entirely clear to me what's wrong about the pair/tuple annotations... Do you mean that MSVC's std::pair and tr1::tuple now accidentally require all of their template arguments to be DefaultConstructible, if only one of them is activated for Swaptimization?

Thursday, August 28, 2008 7:54 PM by Stephan T. Lavavej [MSFT]

# re: TR1 Fixes In VC9 SP1

Yes, which breaks conformant code, which is bad. The annotation is correct from a performance perspective, but we forgot that the Swaptimization has the additional requirement of a default constructor.

Thursday, September 04, 2008 5:02 PM by Niels Dekker

# re: TR1 Fixes In VC9 SP1

Can you please give an indication of when this "swap hotfix" would be available? At my work (www.lkeb.nl), it is planned to apply SP1 later this month. (We're using VC9.) Would you recommend waiting for the hotfix before applying SP1? Please also provide a way to distinguish between a hotfixed and a non-hotfixed installation, by means of a macro or version number.

Monday, September 08, 2008 6:43 PM by Stephan T. Lavavej [MSFT]

# re: TR1 Fixes In VC9 SP1

[Niels Dekker]

> Can you please give an indication of when

> this "swap hotfix" would be available?

Not yet. I can't even promise that we'll ship a hotfix (although I certainly want to).

> At my work (www.lkeb.nl), it is planned to apply

> SP1 later this month. (We're using VC9.) Would you

> recommend waiting for the hotfix before applying

> SP1?

If you're using VC9 RTM, then you can upgrade to VC9 SP1. (The only known regression there is vector<pair<no-default-ctor, something-fast-swappable> >.)

If you're using VC9 Feature Pack Refresh, then you can upgrade to VC9 SP1 if you're not yet using vector<function<FT> >.  If you are, then you'll be hit by this bug, and you'll either need to use a workaround or hold off on upgrading to VC9 SP1.

> Please also provide a way to distinguish between a

> hotfixed and a non-hotfixed installation, by means

> of a macro or version number.

_MSC_FULL_VER and _MSC_BUILD completely identify the compiler version. I believe that the compiler version would be incremented for such a hotfix, but I'm not sure. If we simultaneously hotfix the function::swap(), pair/tuple, and array issues, then the hotfix will certainly be identifiable by looking at how pair, tuple, or array is annotated.

Thursday, September 18, 2008 2:44 PM by CMWoods

# re: TR1 Fixes In VC9 SP1

Any update on whether the team has decided whether or not a hotfix (or better) to address these various issues will be made?

Friday, September 19, 2008 8:20 PM by Stephan T. Lavavej [MSFT]

# re: TR1 Fixes In VC9 SP1

No promises, but Magic 8-Ball says: Signs point to yes.

I merged (function) and wrote (pair, tuple, array, random) the fixes last night, in my pajamas, in about 5 minutes. The other steps of the hotfix process will take longer.

We write VCBlog posts when hotfixes are publicly available, like we did for the Intellisense hotfix, so stay tuned.

Wednesday, December 17, 2008 12:05 PM by Visual C++ Team Blog

# VC9 SP1 Hotfix For The vector<function<FT>> Crash

Back in August, I blogged about the TR1 fixes in VC9 SP1 . An observant reader, grokbrsm, commented that

New Comments to this post are disabled
 
Page view tracker