Sign in to follow this  
Hodgman

tr1::function buggy on MSVC9?

Recommended Posts

Hodgman    51328
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]

Share this post


Link to post
Share on other sites
Hodgman    51328
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...

Share this post


Link to post
Share on other sites
msharpe    122
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().

Share this post


Link to post
Share on other sites
Hodgman    51328
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 SP
Hotfix for Microsoft Visual Studio 2008 Professional Edition - ENU (KB944899) KB944899
Hotfix for Microsoft Visual Studio 2008 Professional Edition - ENU (KB945282) KB945282
Hotfix for Microsoft Visual Studio 2008 Professional Edition - ENU (KB946040) KB946040
Hotfix for Microsoft Visual Studio 2008 Professional Edition - ENU (KB946308) KB946308
Hotfix for Microsoft Visual Studio 2008 Professional Edition - ENU (KB946344) KB946344
Hotfix for Microsoft Visual Studio 2008 Professional Edition - ENU (KB946581) KB946581
Hotfix for Microsoft Visual Studio 2008 Professional Edition - ENU (KB947171) KB947171
Hotfix for Microsoft Visual Studio 2008 Professional Edition - ENU (KB947173) KB947173
Hotfix for Microsoft Visual Studio 2008 Professional Edition - ENU (KB947180) KB947180
Hotfix for Microsoft Visual Studio 2008 Professional Edition - ENU (KB947540) KB947540
Hotfix for Microsoft Visual Studio 2008 Professional Edition - ENU (KB947789) KB947789
Hotfix for Microsoft Visual Studio 2008 Professional Edition - ENU (KB948127) KB948127
Microsoft Visual Studio 2008 Professional Edition - ENU Service Pack 1 (KB945140) KB945140
Microsoft Visual Studio 2008 Professional Edition - ENU Service Pack 1 (KB947888) KB947888
Microsoft 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]

Share this post


Link to post
Share on other sites
daviangel    604
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

Share this post


Link to post
Share on other sites
scjohnno    236
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.

Share this post


Link to post
Share on other sites
Cwiddy    150
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

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this