Archive for the ‘C++’ Category

More C++ Idioms

Monday, August 2nd, 2010

Hallo,

wer sich für C++ interessiert und seinen Horizont erweitern will sollte mal auf die Seite “More C++ Idioms” auf wikibooks.org anschauen.

Dabei kann man nicht nur bekannte C++ Pattern wie Empty Base Class Optimization oder Copy-and-swap wiederholen sondern sich auch interessante neue Ideen aneignen, wie z.B. Safe bool.

Aber Achtung: im Gegensatz zu der Angabe auf der Seite würde ich die Anforderungen an die Leser nicht als “intermediate” sondern als “advanced” einstufen.

Viele Grüße,
Andreas

Technorati Tags: ,

Visual C++ 2010 kann nur für das .NET Framework 4.0 Code erzeugen

Sunday, June 20th, 2010

Hallo,

vor einiger Zeit bin ich zu dem Schluss gekommen, meine Entwicklungsumgebung auf Basis von Windows 7 und Visual Studio 2010 neu aufzusetzen. Nach der Konvertierung der C++ Projekte wurde in einer Solution mit C# und C++ Projekten folgende Warnung ausgegeben:

Warnung    2    Auf das Projekt “xxx” kann nicht verwiesen werden.  Das Projekt, auf das verwiesen wird, hat eine höhere Frameworkversion (”4.0″) als Ziel.

In der ursprünglichen Solution war für alle Projekt das .NET Framework 2.0 als Targetversion eingetragen. Das war aus gutem Grund so, da die erstellte Anwendung für den Download über das Internet bereit gestellt wird und auf möglichst vielen Computern ohne weitere Vorbereitungen eingesetzt werden soll.

Eine Erklärung für die implizite Erhöhung der Targetversion für Managed C++ Projekte finden sich in diesem Blog-Eintrag mit einem “Visual Studio 2010 C++ Project Upgrade Guide”:

After conversion, managed C++ projects will target the 4.0 Framework by default.  The reason behind this design is that the VS2010 compiler cannot target Framework 2.0, 3.0 or 3.5. The VS2008 compiler must be used to target 2.0, 3.0 or 3.5. To make the converted C++ application build out of box, we decided to move the TargetFrameWorkVersion to 4.0 by default for C++ applications.

Oops! Mit Visual Studio 2010 können keine Managed C++ Anwendungen für .NET Framework Versionen < 4.0 erstellt werden!

Dagegen hilft nur eines:

The VS2008 compiler must be used to target 2.0, 3.0 or 3.5.

D.h. man ist gezwungen, Visual C++ 2008 zusätzlich zu installieren, wenn man Managed C++ Komponenten erstellen will, die .NET Frameworks < 4.0 als Target haben. Die Änderung der Zielversion geht noch nicht mal in der IDE sondern nur durch Änderung der Projektdateien in einem Editor.

Ich betrachte das als erhebliche Einschränkung, da man in diesem Fall Visual Studio 2008 zusätzlich installieren (und ggf. kaufen) muss, sondern dann auch die schönen neuen C++ Features des Compilers nicht mehr nutzen kann.

Generell habe ich den Eindruck, dass Microsoft sich mit Visual Studio 2010 etwas übernommen hat, und irgendwann einfach die Produktfreigabe beschlossen hat, obwohl es noch viele Probleme und Einschränkungen gab (z.B. wie im obigen Blog-Eintrag beschrieben, oder das Fehlen von Intellisense für Managed C++ oder die unscharfe Erscheinung der Default-Fonts auf manchen Betriebsystemen oder der erhöhte Speicherbedarf  oder das aus nicht nachvollziehbaren Gründen umgestellte Hilfesystem, das jetzt eigentlich unbrauchbar ist.).

Auf der Haben-Seite steht für mich ganz klar der neu implementierte Support für Intellisense (bei native C++ Projekten). Das funktioniert jetzt viel besser als mit Visual C++ und verbessert die Produktivität spürbar.

Viele Grüße,
Andreas

Technorati Tags:

Wie kann man native Methoden in managed C++ Klassen nutzen?

Sunday, October 4th, 2009

Hallo,

Microsoft hat mit der Einführung des .NET-Frameworks auch C++-Erweiterungen (C++/CLI) definiert, mit denen vorhandener C++ source code für .NET-Anwendungen verfügbar gemacht werden kann.

Die Intention dabei war die Steigerung der Akzeptanz des .NET-Frameworks, da es relativ einfach gemacht wird, bereits vorhandenen C++ code in .NET-Anwendungen zu integrieren. Meiner persönlichen Erfahrung nach geht das sehr gut, d.h. es ist ziemlich einfach vorhanden C++ code mit C++/CLI .NET-tauglich zu machen und die entstandenen Assemblys haben keine nennenswerten Einschränkungen (abgesehen davon, dass sie nur für die Plattform geeignet sind, für die der native code kompiliert wurde).

Der übliche Weg besteht darin eine neue Assembly zu erstellen, die C++/CLI Klassen (und ggf. native Klassen) enthält. Diese Klassen rufen dann den eigentlichen legacy code, typischerweise in bereits vorhandenen Libraries/DLLs.

Folgende Frage stellt sich bei der Erstellung eines Managed C++ Wrappers um vorhanden C++ code schnell:

Wie kann ich innerhalb des .NET-Wrappers native Datenstrukturen zwischen managed Klassen austauschen?

Dies ist grundsätzlich nicht ohne weiteres möglich, da in der öffentlichen Schnittstelle nur CLR-kompatible Datentypen verwendet werden dürfen (ansonsten könnten nicht alle Elemente der Schnittstelle von anderen .NET kompatiblen Komponenten konsumiert werden).

Es ist allerdings möglich, private Methoden zu definieren, die nicht CLR-konforme Datentypen konsumieren oder zurückgeben dürfen. Damit solche Methoden von anderen Klassen in der C++/CLI Wrapper-Assembly gerufen werden dürfen, müsste man alle diese Klassen als friend definieren, was eine etwas unbefriedigende Lösung ist.

Diese Überlegung führt aber zur optimalen Lösung: die Deklaration der entsprechenden Methoden als public private. public private ist in C++/CLI die Entsprechung zu internal in C# und bedeutet “sichtbar innerhalb der Assembly”.
Da die entsprechenden Methoden nur von den C++-Klassen innerhalb der Wrapper-Assembly gerufen werden, gibt es keinen Grund sie zu verbieten (was der Compiler dann auch nicht macht).

Viele Grüße,
Andreas

Technorati Tags: ,

Destruktor nicht gerufen in mixed mode C++ Anwendungen mit Visual C++ 2008

Monday, February 9th, 2009

Hallo,

in C++ gibt es ja das Resource Aquisition Is Initialization (RAII) pattern. Der Kern dieses Patterns besteht darin, dass ein Objekt bereits bei der Konstruktion die Ownership für eine Resource übernimmt und diese Resource bei seiner Zerstörung wieder frei gibt. Man wendet dieses pattern an, um Resourcen wie allokierten Speicher oder file handles sicher freizugeben. Dabei mancht man sich zu nutze, dass in C++ der Destruktor eines Objektes deterministisch aufgerufen wird, z. B. auch im Falle eine exception.

Dieses pattern ist sehr wichtig, um zuverlässige und robuste Software in C++ zu schreiben und ich nutze es regelmäßig. Nun hatte ich vor einiger Zeit in einem der Unittests in der Software, die ich für mein Unternehmen EmPowerTec schreibe, einen seltsamen Fehler in einem Unittest. Nach einer längeren Debugging-Session sah es so aus, als würden die Destruktoren für Objekte die in einer Methode auf dem Stack angelegt waren, beim Verlassen der Methode nicht mehr gerufen. Ein solches Verhalten führt mit Sicherheit zu Fehlern, wenn das RAII Pattern genutzt wird. Zunächst war ich darüber verblüfft, da ich mir nicht vorstellen konnte, dass ein derartig fundamentales Verhalten vom Microsoft C++ Compiler nicht richtig implementiert war. Tatsächlich war das aber der Fall, wie in folgendem Knowledge Base Eintrag beschrieben:

http://social.msdn.microsoft.com/forums/en-US/vclanguage/thread/8324a598-ad05-40e1-a271-6f64ce3b6008

Wie man dem Thread entnehmen kann, tritt das Problem auf, wenn man von einer C++/CLI Library eine native C++ library aufruft und diese mit inkompatiblen Einstellungen für das Exception handling übersetzt hat.

Und die Moral von der Geschicht,
Trau’ keinem Compiler nicht,

Unittests sollst Du machen,
Sonst hast Du nichts zu lachen

Viele Grüße,
Andreas

Technorati Tags: ,