tr1::function buggy on MSVC9?

Started by
7 comments, last by Hodgman 13 years, 11 months ago
I'm writing an example program to demonstrate function and bind to some other people, but pushing functions into a vector is causing crashes. In the past I've always used boost's implementation of these - for this example I'm using the ones from MSVC 2008 though. In the following example, there's 3 commented out lines where I manually set the size of the vector and use assignment to hard-coded indices -- if I use those lines instead of the equivalent push_back version, it works fine. Does anyone know why the push_back version would be crashing? The crash happens either when I try to call the functions in the vector, or if I disable that code, the crash happens when the vector goes out of scope.
#include <functional>
#include <algorithm>
#include <vector>

using namespace std;
using namespace tr1;
using namespace placeholders; 

void MyCallback()
{
  printf( " called MyCallback()\n" );
}

void MyCallback2( int number )
{
  printf( " called MyCallback2(%d)\n", number );
}

int main(int argc, char* argv[])
{
    printf( "events += MyCallback\n" );
    printf( "events += MyCallback2, 42\n" );

    //vector<function<void()>> events(2);
    //events[0] = &MyCallback;
    //events[1] = bind( &MyCallback2, 42 );

    vector<function<void()>> events;
    events.push_back( &MyCallback );
    events.push_back( bind( &MyCallback2, 42 ) );

    struct call { void operator()( const function<void()>& f ) {
      f();
    }};
    printf( "Calling foreach events\n" );
    for_each( events.begin(), events.end(), call() );
    printf( "\n" );

    printf( "Press enter..." );
    getchar();
    return 0;
}
[Edited by - Hodgman on April 28, 2010 10:09:54 PM]
Advertisement
Ok this keeps getting weirder... This example crashes too, but if I un-comment the call to reserve, then it works fine.
int main(int argc, char* argv[]){    vector<function<void()>> events;    //events.reserve(2);    events.push_back( &MyCallback );    events.push_back( bind( &MyCallback2, 42 ) );    struct call    {        void operator()( const function<void()>& f )        {            f();        }    };    for_each( events.begin(), events.end(), call() );    return 0;}
Something to do with reallocating the vector's internal buffer???
AFAIK, reserve should never fix a crash! Unless I'm doing something really wrong...
Are you using VS2008 RTM or SP1? I tried the second example with SP1 and everything worked as it should without the call to reserve().
Thanks for testing it, though now I'm more worried if it works on some MSVC9 installs, and not others...

Yeah I think SP1 is installed :/
This is from help->about
Microsoft Visual Studio 2008 Version 9.0.30729.1 SPHotfix for Microsoft Visual Studio 2008 Professional Edition - ENU (KB944899)   KB944899Hotfix for Microsoft Visual Studio 2008 Professional Edition - ENU (KB945282)   KB945282Hotfix for Microsoft Visual Studio 2008 Professional Edition - ENU (KB946040)   KB946040Hotfix for Microsoft Visual Studio 2008 Professional Edition - ENU (KB946308)   KB946308Hotfix for Microsoft Visual Studio 2008 Professional Edition - ENU (KB946344)   KB946344Hotfix for Microsoft Visual Studio 2008 Professional Edition - ENU (KB946581)   KB946581Hotfix for Microsoft Visual Studio 2008 Professional Edition - ENU (KB947171)   KB947171Hotfix for Microsoft Visual Studio 2008 Professional Edition - ENU (KB947173)   KB947173Hotfix for Microsoft Visual Studio 2008 Professional Edition - ENU (KB947180)   KB947180Hotfix for Microsoft Visual Studio 2008 Professional Edition - ENU (KB947540)   KB947540Hotfix for Microsoft Visual Studio 2008 Professional Edition - ENU (KB947789)   KB947789Hotfix for Microsoft Visual Studio 2008 Professional Edition - ENU (KB948127)   KB948127Microsoft Visual Studio 2008 Professional Edition - ENU Service Pack 1 (KB945140)   KB945140Microsoft Visual Studio 2008 Professional Edition - ENU Service Pack 1 (KB947888)   KB947888Microsoft Visual Studio 2008 Professional Edition - ENU Service Pack 1 (KB948484)   KB948484

[EDIT]
Here's my full source code that you can c&p into a new console application
// TestTR1_2.cpp : Defines the entry point for the console application.//#include "stdafx.h"#include <functional>#include <algorithm>#include <vector>using namespace std;using namespace tr1;using namespace placeholders; void MyCallback(){  printf( " called MyCallback()\n" );}void MyCallback2( int number ){  printf( " called MyCallback2(%d)\n", number );}class Test{public:  Test() : member(1337) {}  int member;  void PrintNumbers( int number )  {    printf( " called Test::PrintNumbers(%d), member = %d\n", number, member );  }};int _tmain(int argc, _TCHAR* argv[]){  {    function<void()>    eventNoArgs;    printf( "eventNoArgs = MyCallback\n" );    eventNoArgs = &MyCallback;    printf( "Calling eventNoArgs()\n" );    eventNoArgs();    printf( "\n" );    printf( "eventNoArgs = MyCallback2, 42\n" );    eventNoArgs = bind( &MyCallback2, 42 );    printf( "Calling eventNoArgs()\n" );    eventNoArgs();    printf( "\n" );  }  {    function<void(int)> event1Arg;    Test object;    printf( "event1Arg = MyCallback\n" );    event1Arg = bind( &MyCallback );    printf( "Calling event1Arg(42)\n" );    event1Arg( 42 );    printf( "\n" );    printf( "event1Arg = MyCallback2, arg#1\n" );    event1Arg = bind( &MyCallback2, _1 );    printf( "Calling event1Arg(42)\n" );    event1Arg( 42 );    printf( "\n" );    printf( "event1Arg = Test::PrintNumbers, object, arg#1\n" );    event1Arg = bind( &Test::PrintNumbers, &object, _1 );    printf( "Calling event1Arg(42)\n" );    event1Arg( 42 );    printf( "\n" );  }  {    printf( "events += MyCallback\n" );    printf( "events += MyCallback2, 42\n" );    /*vector<function<void()>> events(2);    events[0] = &MyCallback;    events[1] = bind( &MyCallback2, 42 );*/    vector<function<void()>> events;    //events.reserve(2);    events.push_back( &MyCallback );    events.push_back( bind( &MyCallback2, 42 ) );    printf( "Calling foreach events\n" );    struct call { void operator()( const function<void()>& f ) { f(); }};    for_each( events.begin(), events.end(), call() );    printf( "\n" );  }  printf( "Press enter..." );  getchar();	return 0;}


[Edited by - Hodgman on April 29, 2010 12:59:37 AM]
Seems to work fine on my install of VS2008 here also but chokes on VS2010 with following error:
Error 1 error C2872: 'placeholders' : ambiguous symbol
[size="2"]Don't talk about writing games, don't write design docs, don't spend your time on web boards. Sit in your house write 20 games when you complete them you will either want to do it the rest of your life or not * Andre Lamothe
The full code, pasted directly into a new project in my copy of VS2008, crashes on the for_each(). If I switch it to use Boost.Bind & Boost.Function (v1.36), without any other changes, it works fine.

So yeah, it probably is an implementation bug. I don't have VS2010 to check with, unfortunately.
I don't really know if this is related but I remember seeing this in a blog post

function<FT>::swap() was broken by the Small Functor Optimization in VC9 TR1 (the Feature Pack). This broke vector<function<FT>> in VC9 SP1. "Broken" meant "compiling but crashing".

http://blogs.msdn.com/vcblog/archive/2008/12/17/vc9-sp1-hotfix-for-the-vector-function-ft-crash.aspx
Hah i was going to post that but someone beat me to it :)
Thanks for the info guys. Guess I should just stick to the boost versions for now, as I can be sure they'll work on everyone's installation ;)

This topic is closed to new replies.

Advertisement