简体   繁体   中英

How can I call a function on stack unwind?

What I want to write is something like

void foo()
{
    int a = 5;
    ExecuteOnUnwind eou(bind(&cleanupFunc, a));
}

Such that cleanupFunc(a) is called when the function returns or an exception is thrown. Is there some facility already available that will do this for me? I wasn't able to find the right phrase to google, but it seems like there is probably something out there that does this. If not, I quickly put together a solution below. Oddly enough it doesn't seem to work in release mode, but does work in debug on vc10 - how can i tweak the implementation to make it work consistently on both without risking additional calls to temporaries?

Edit: fix involves using shared_ptr; also alleviates any concerns about temporary destruction. new code is below

template <typename T>
struct ExecuteOnUnwindHelper
{   
    ExecuteOnUnwindHelper(const T & _functor) : mFunctor(_functor)
    {
    }

    ~ExecuteOnUnwindHelper()
    {
        mFunctor();
    }

    const T & mFunctor;
};

template <typename T>
boost::shared_ptr<ExecuteOnUnwindHelper<T>> ExecuteOnUnwind(const T & _functor)
{
    return boost::shared_ptr<ExecuteOnUnwindHelper<T>>(new ExecuteOnUnwindHelper<T>(_functor));
}

void cleanupFunc(int a)
{
    wcout << L"cleanup" << endl;
}

void foo()
{
    int a = 5;
    auto eou = ExecuteOnUnwind(boost::bind(&cleanupFunc, 5));
}

int main()
{
    foo();
    return 0;
}

The compiler must somehow optimize away the creation of the variable on the stack because it thinks it's not used. Maybe it just inlines the call to the function and skips the creation / destruction part (I would say it is the most likely). It thinks the global semantics is preserved, but it's actually not a safe optimization as your example shows.

I think it is a wrong optimization because it obviously changes the high-level semantics.It would be interesting to test with various compilers. I will try with VS2012 when I get a chance at home.

Anyway, to force it to go through a creation / destruction sequence, just use a boost::shared_ptr and it will take care of creating the object and destructing it when the object goes out of scope, be it through a return statement or through an exception throw.

The simplest solution would be to put the required functionality into the destructor of a type. There shouldn't be a need for auto/smart pointers in your case and the stack would been sufficient and may remove the compiler issue you may be experiencing.

class ExecuteOnUnwind
{
public:
~ExecuteOnUnwind()
{
/** Do something */
}

int data;

};

void foo()
{
  ExecuteOnUnwind runOnExit;

/** Functions code here */
runOnExit.data = 5;

}

If this didn't/doesn't work then you could disable the optimisation around the affected code (ie destructor).:

#pragma optimize( "", off )
...
#pragma optimize( "", on )

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM