Succinct introduction to C++/CLI for C#/Haskell/F#/JS/C++/... programmer
I'm trying to write integrations with the operating system and with things like active directory and Ocropus.
I know a bunch of programming languages, including those listed in the title. I'm trying to learn exactly how C++/CLI works, but can't find succinct, exact and accurate descriptions online from the searching that I have done. So I ask here.
Could you tell me the pitfalls and features of C++/CLI? Assume I know all of C# and start from there. I'm not an expert in C++, so some of my questions' answers might be "just like C++", but could say that I am at C#. I would like to know things like:
- Convert开发者_JAVA百科ing C++ pointers to CLI pointers,
- Any differences in passing by value/doubly indirect pointers/CLI pointers from C#/C++ and what is 'recommended'.
- How do gcnew, __gc, __nogc work with
- Polymorphism
- Structs
- Inner classes
- Interfaces
- The "fixed" keyword; does that exist?
- Compiling DLLs loaded into the kernel with C++/CLI possible? Loaded as device drivers? Invoked by the kernel? What does this mean anyway (i.e. to load something into the kernel exactly; how do I know if it is?)?
- L"my string" versus "my string"? wchar_t? How many types of chars are there?
- Are we safe in treating chars as uint32s or what should one treat them as to guarantee language indifference in code?
- Finalizers (~ClassName() {}) are discouraged in C# because there are no garantuees they will run deterministically, but since in C++ I have to use "delete" or use copy-c'tors as to stack allocate memory, what are the recommendations between C#/C++ interactions?
- What are the pitfalls when using reflection in C++/CLI?
- How well does C++/CLI work with the IDisposable pattern and with SafeHandle, SafeHandleZeroOrMinusOneIsInvalid?
- I've read briefly about asynchronous exceptions when doing DMA-operations, what are these?
- Are there limitations you impose upon yourself when using C++ with CLI integration rather than just doing plain C++?
- Attributes in C++ similar to Attributes in C#?
- Can I use the full meta-programming patterns available in C++ through templates now and still have it compile like ordinary C++?
- Have you tried writing C++/CLI with boost?
- What are the optimal ways of interfacing the boost library with C++/CLI; can you give me an example of passing a lambda expression to an iterator/foldr function?
- What is the preferred way of exception handling? Can C++/CLI catch managed exceptions now?
- How well does dynamic IL generation work with C++/CLI?
- Does it run on Mono?
- Any other things I ought to know about?
Note: I'm really asking about the peculiarities of C++/CLI, its trapdoors.
Converting C++ pointers to CLI pointers
CLI types don't have to be pointers. In C++/CLI handle (^) is used.
Any differences in passing by value/doubly indirect pointers/CLI pointers from C#/C++ and what is 'recommended'.
If you need better interoperability with C#, avoid using pointers. Use all the pointer related stuff in C++/CLI and expose only managed types so that C# applications can use it easily.
The "fixed" keyword; does that exist?
pin_ptr<>
is the equivalent.
Finalizers (~ClassName() {}) are discouraged in C# because there are no garantuees they will run deterministically, but since in C++ I have to use "delete" or use copy-c'tors as to stack allocate memory, what are the recommendations between C#/C++ interactions?
C++/CLI supports deterministic resource management. When you write a destructor, compiler will implement IDisposable
interface on the class and convert destructor into Dispose()
method. delete will call this Dispose()
to do the resource de-allocation. Because of this, you don't have issues in using it from C#. You can wrap the usage in using
statement in C# which will ensure call on Dispose
.
Attributes in C++ similar to Attributes in C#?
Yes they are similar.
Can I use the full meta-programming patterns available in C++ through templates now and still have it compile like ordinary C++?
Yes. C++/CLI supports templates on ref classes. You can use metaprogramming techniques like you do in standard C++. But these won't be portable to C#.
Have you tried writing C++/CLI with boost?
C++/CLI has access to the whole .NET framework. I don't think boost helps much here.
To start with, you're confusing the now-defunct "Managed extensions for C++" which had __gc and __nogc keyword, with the new and currently supported C++/CLI language, which finally provides a proper distinction between pointers (native) and handles (managed objects, they're actually implemented as pointers into garbage collected memory where .NET objects live, but you shouldn't think of them as pointers because they get adjusted automatically by the garbage collector). The two types of pointers are completely distinct, only builtin types are compatible with both and then you just box them to get a handle. You can never have a handle pointing outside the managed heap and you can only get a native pointer into the managed heap for the duration of a pin_ptr lifetime (local scope only). A managed class can hold a pointer to native memory, just like C# can have IntPtr members. Native types can hold handles to managed objects using the gcroot templated type, which wraps System::GCHandle.
The Microsoft C++/CLI compiler is capable of generating either pure MSIL or a mixture of MSIL and native code, depending on whether you use /clr or /clr:pure or /clr:safe (the last restricts /clr:pure to produce only verifiable MSIL). The answers to most of your other questions depend on which of these modes it is in. For example, any MSIL it produces will run on Mono, but mixed native and MSIL won't, because it relies on internals of the Microsoft .NET runtime.
Any limitations apply only to managed types (e.g. ref class, enum class) created with C++/CLI. Native types, even when compiled to pure MSIL, have the full flexibility of the C++ language including multiple inheritance, templates, etc.
C++/CLI catches managed exception types in both native and managed code (/clr forces the /EHa compiler option).
C++/CLI provides a stack semantics syntax (declare a variable whose type doesn't include the ^ suffix meaning handle). This is possible for both local variables and members of managed types. The compiler will automatically produce calls to IDisposable::Dispose for types which implement it in all the usual places (like a C# using block for local variables, automatically create an IDisposable implementation in managed types which calls Dispose on all members).
Lambdas aren't available yet, because in the next version of Visual Studio (2010) they will be added using the syntax defined by the upcoming C++ standard.
You can't run managed code in kernel mode regardless of what compiler you use, C++/CLI changes nothing in this area.
You really have way too many points here for a single question. If you really want me to go through every point I will, but it's going to be a series of blog entries and I'll just leave a link here.
精彩评论