Briefly and quickly understand the C ++ CLI

It so happened that, as the need arises, I have to use C ++ / CLI intensively and, accordingly, quite often explain to beginners that this is how it works, how to use it, and why at all. So over time, there was a desire to write an article with an overview of the language, answers to some common questions and show places where the rake can successfully go.

What is it?



When Microsoft created the .Net platform, it decided to let programmers write for it in several existing languages, the syntax of which had some changes - VB, C ++. It will be about the latter. More precisely, if my memory serves me right, in the first edition the language was called C ++ with managed extensions. The name, as it were, hints at the essence - here we have given you pluses with extensions and now you can develop for .Net using the already well-known C ++, while leaving all the power of the source language.Actually, the first version of the syntax extension was terrible a little more than completely, and made the code look like an attempt to encode and send into space a dialogue between Zhirinovsky and Chernomyrdin:
//объявляем управляемый класс
public __gc class Class1
{
public:
  // метод, принимающий int по ссылке и управляемый массив
  int Method1(__gc int &refValue, __gc int[] managedArr);
};

* This source code was highlighted with Source Code Highlighter.

In addition, in this syntax there were no differences between a pointer to a native type and a managed type (in both cases the “*” was used), there was no keyword to indicate a null pointer, and so on. This prompted Microsoft to create a new revision of the language, which will be discussed in this article.
Note: these two versions of the syntax are called, oddly enough, “old syntax” and “new syntax”, and which one can be used in the project compilation settings. However, when creating new assemblies, it is better to use the new syntax, since the old one is marked as obsolete and simply bad.

Why is it necessary?



1) With the help of this language, a spherical programmer in a vacuum will be able to develop a full-fledged .Net application on his favorite pluses. Honestly, it’s hard for me to imagine this pervert, and Microsoft clearly doesn’t contribute to this approach even if it doesn’t do visual components under C ++. Actually, he does it right, because for such purposes there are more expressive languages, the same C #. So this is a theoretical possibility.

2) You can call the code already written on the pros. Indeed, since we still have all the features of regular C ++, we can create managed wrappers for existing classes on native pluses. This gives much greater opportunities for calling unmanaged code than PInvoke, which does not know how to work with classes.

3) You can write modules in C ++ CLI where performance is critical. Indeed, among the entire zoo of languages ​​for .Net, C ++ is unique in that you can write code on it that directly uses memory allocation and freeing, and working with pointers. For example, like this:
//управляемый класс, который может потом использоваться любой .Net–сборкой
public ref Class1
{
public:
  //этот метод так же можно использовать во всех .Net-сборках
  void Method1();
  {
    BYTE *buff = new BYTE[100];

    //do smth

    delete[] buff;
  }
};

* This source code was highlighted with Source Code Highlighter.


How does it work?



Everything is very simple. When compiling code in C ++ / CLI, an assembly is obtained containing both MSIL code and machine instructions, into which lines written on "clean" pluses have turned. “But what about cross-platform?” You ask, and you will be absolutely right. No way. In particular, this means that it will not be possible to collect the same binary for 32 and 64 bit versions (to collect everything under "Any CPU"). This is the price paid for using all the features of C ++. Naturally, this refers to the case when a mix of managed and unmanaged code is used. There are several compilation options in total:
• / clr - support for managed and native code using the new syntax.
• / clr: pure - native code is not supported. However, you can use unsafe) code to the extent that it can be done, for example, in C # assemblies using the unsafe directive.
• / clr: safe - Only managed safe code. The analogue is compiling a C # assembly without using unsafe.
• / clr: oldSyntax - analogue of / clr, only the old syntax is used.

What does it look like?



Here are examples of comparing the basic constructs for C # and C ++ / CLI.

Class declaration

C #:
public sealed class Class1 : Class2

* This source code was highlighted with Source Code Highlighter.

C ++ / CLI:
public ref class Class1 sealed : Class2

* This source code was highlighted with Source Code Highlighter.


Structure Declaration

C #:
public struct Class1 : IEquatable

* This source code was highlighted with Source Code Highlighter.

C ++ / CLI:
public value class Class1 : IEquatable

* This source code was highlighted with Source Code Highlighter.


Interface Announcement

C #:
public interface ISomeInterface

* This source code was highlighted with Source Code Highlighter.

C ++ / CLI:
public interface class ISomeInterface

* This source code was highlighted with Source Code Highlighter.


Listing announcement

C #:
public enum Enum1
    {
      Val1,
      Val2
    }

* This source code was highlighted with Source Code Highlighter.

C ++ / CLI:
public enum class Enum1
    {
      Val1,
      Val2
    }

* This source code was highlighted with Source Code Highlighter.


Creating a managed entity

C #:
object obj = new object();

* This source code was highlighted with Source Code Highlighter.

C ++ / CLI:
Object ^obj = gcnew Object();

* This source code was highlighted with Source Code Highlighter.

In C ++ / CLI, “^” is used instead of “*” to refer to managed objects. It is very convenient to distinguish between objects that you later need to delete and those that you don’t need. Also, when creating a local reference object, you can use the semantics of the stack:
Object obj ();
This makes sense either when using objects that implement IDisposable (we will discuss this later) or for value types. Note that in terms of storing and using value types, C ++ / CLI gives more freedom than C #, since the programmer can choose whether to use a link or a value. Thus, it is quite possible in some situations to save on the number of boxing / unboxing operations.

Creating a managed array

C #:
object[] arr = new object[100];

* This source code was highlighted with Source Code Highlighter.

C ++ / CLI:
array<Object ^> ^arr = gcnew array<Object ^>();

* This source code was highlighted with Source Code Highlighter.

Unmanaged arrays are created as usual.

Passing parameters to a method

C #:
void Method(int byValue, ref int byRef, out int outValue);

* This source code was highlighted with Source Code Highlighter.

C ++ / CLI:
void Method(int byValue, int %byRef, [out] int %outValue);

* This source code was highlighted with Source Code Highlighter.

As you can see from this example, if “^” is an analogue of “*” from regular C ++, then “%” is an analogue of “&”. Moreover, the analogy is very accurate and can be seen not only when passing parameters, but also when receiving a link, for example:
void Method(ValueType val)
{
  ValueType ^ref = %val;
}

* This source code was highlighted with Source Code Highlighter.


Method override

C #:
override void Method();
* This source code was highlighted with Source Code Highlighter.

C ++ / CLI
virtual void Method() override;

* This source code was highlighted with Source Code Highlighter.


IDisposable template implementation

WITH#:
class Class1 : Disposable
{
  public void Dispose()
  {
    this.Dispose(true);

    GC.SuppressFinalize(this);
  }

  protected virtual void Dispose(bool disposing)
  {
    if (disposing)
    {
      //release managed resources
    }
    
    //release unmanaged resources
  }

  ~Class1()
  {
    this.Dispose(false);
  }  
}

* This source code was highlighted with Source Code Highlighter.

C ++ / CLI:
ref class Class1
{
public:
  //Эквивалент Dispose
  ~Class1()
  {
    //release managed resources

    //call finalizer
    this->!Class1();
  }

  //Аналог финализатора
  !Class1()
  {
    //release unmanaged resources
  }
}

* This source code was highlighted with Source Code Highlighter.

In C ++ / CLI, the compiler implements part of the Disposable template for us, and this in appearance differs from the typical implementation of the interface. Moreover, the same compiler will not allow you to implement IDisposable directly. However, when you get used to it, you understand that this behavior is quite logical - eliminates the need to write a bunch of repeating code. Also, in their desire to make the release of resources similar to ordinary C ++, the creators of the language went even further and there can be an explicit call to Dispose in two ways:
obj->~Class1();

* This source code was highlighted with Source Code Highlighter.

and
delete obj;
* This source code was highlighted with Source Code Highlighter.

You can also use the semantics of the stack for guaranteed cleaning of resources:
C ++ / CLI:
{
  A();  

  Class1 obj;
  
  B();
}

* This source code was highlighted with Source Code Highlighter.
corresponds to
C #:
{
  A();

  using (Class1 obj = new Class1())
  {
    B();
  }
}

* This source code was highlighted with Source Code Highlighter.


What remains behind the scenes?



It is clear that it was not possible to put everything in one article. Such issues as remained unexamined:
• Syntax of delegates, properties, extension methods, foreach, etc.
• Juggling from managed to unmanaged and back by objects, arrays, etc.
• What is supported and not from what is in C # and in regular C ++
• Features of compiling applications with C ++ / CLI assemblies
• Performance issues. When and how can I get a win? Where can you suddenly lose?

What to read?



1. Comparison of C # and C ++ syntax: www.cyberforum.ru/cpp-cli/thread83662.html
2. The main specific language constructions: msdn.microsoft.com/en-us/library/xey702bw.aspx
3. Migration to C ++ / CLI: msdn.microsoft.com/en-us/library/ms235289.aspx

Conclusion



Among all other languages ​​under .Net, C ++ / CLI is quite specific. It hardly makes sense to develop a standard .Net application on it, but as a communication with existing C ++ code or for optimization tasks, it is.

Also popular now: