C++/CLI quiz: Answer

In one of my last post, I asked the question, how does the callstack look like.
It was is simple unmanaged class with a virtual function. If you had executed the sample program, and set a breakpoint into the “Foo” method, you can see in the callstack-window of VS, the following callstack:
Callstack of (native) virtual function in managed code

As you can see, there are two transitions which we had not expected. One transition to native code, and one transition back to managed code.

And if you put a “printf” statement into the copy-constructor of the V-struct, you will see that the copy-constructor is called tiwce! This can have very strong performance effects…

So what might be the course of this “unnecessary” transitions?

The problem is: We have written an unmanaged virtual function as a managed function (the whole file is compiled with /clr). This means, that all unmanaged virtual functions will have two entry points. One entry point is for the “native” v-table call (thiscall); and the other is for the managed entry (clrcall).

If you call a unmanaged virtual function in a managed world, the compiler does not know which function must be callled. This is only examined at runtime through the v-table. Therefor the compiler needs to call the native function which uses the v-table. Then this “proxy”-function is calling the managed entry point. And because there are two functiions involved, the copy-constructor the the V-struct is called twice.

Conclusion:
Be aware that virtual functions in unmanaged classes which are compiled with /clr might lead to performance decrease.
If you have a big codebase, you should only enable /clr for specific files which implements the “wrapper”.
Be aware that every managed/unmanaged transition has additional execution-costs on your application. So prevent this transitions as much as possible.

Leave a Reply

Your email address will not be published.

Captcha *