Service: C/C++ Tipps: Variableninitialisierung per Vorlagenklasse sicherstellen


Wer sich seine 'Programmierersporen' mit Visual Basic 6.0 und dessen Vorgängerversion verdient hat und dann auf C++ umsattelt, ist Anfangs immer wieder sprachlos darüber, wie kompliziert selbst einfachste Aufgaben sein können.

Andererseits haben eingefleischte C++ Programmierer, die gezwungen sind sich mit VB auseinanderzusetzen, stets ein ungutes Gefühl, weil so vieles im Hintergrund geschieht, über das man keine Kontrolle hat. Ein Beispiel ist die Variableninitialisierung.

Beispielhafte Darstellung der Unterschiede bei der Deklaration einer Integer-Variablen (der unterschiedliche Wertebereich bleibt hier außer Acht):

Art der Deklaration, Kontext VB C++
Deklaration Initialwert Anmerkung Deklaration Initialwert Anmerkung
Ohne Initialisierung, Funktionsebene Dim l As Long 0 Jede Variable wird mit 0 initialisiert. Initialisierung auf abweichenden Wert nur mit gesonderter Anweisung long l; unbestimmt Auf Funktionsebene können Initialisierung und Deklaration verbunden werden. Auf Modulebene nur mit gesonderter Anweisung
Mit Initialisierung, Funktionsebene Dim l As Long
l = 20
0 long l = 20; 20;
Ohne Initialisierung, Modulebene Private m_l As Long 0 long m_l; unbestimmt
Mit Initialisierung, Modulebene Private m_l As Long
0 long m_l; unbestimmt

Wie aus der Tabelle ersichtlich, ist es in VB unmöglich, mit einer nicht initialisierten Variablen zu arbeiten. Bis VB 6.0 war es jedoch auch auf Funktionsebene nicht möglich, unmittelbar mit der Deklaration eine Zuweisung zu schreiben.

In C++ anderseits kann man zwar auf Funktionsebene unmittelbar mit der Deklaration eine Zuweisung schreiben. Jedoch: Wenn man es vergisst, hat man unter Umständen ein gewaltiges Problem, denn eine nicht initialisierte Variable ist wie eine Katastrophe, die auf ihren Ausbruch wartet (*). Dies gilt für Deklarationen auf Modulebene in einem gewissen Sinne erst recht, weil hier die Initialisierung an anderer Stelle als die Deklaration erfolgen muss.

Die vorlagenbasierte Klasse SmartTypesT

Dies ist der Versuch einer Lösung des 'Initialisierungsproblems' in C++. Hier besteht sicher noch Optimierungspotential. Z.B. weitere Operatoren, Leistungsoptimierungen und zusätzliche 'typedefs' für weitere Basisdatentypen.

/**
 * Template class which saves the work to initialize base type variables
 * and this way ensures, variables are never uninitialized.
 * @author Ralf Kunsmann (www.kunsmann.de) @date 2007 03 02 (yyyy mm dd)
 */
template<typename T> class SmartTypesT
{
public:
    SmartTypesT()
    {
        t = (T)0;
    }
    SmartTypesT(T init)
    {
        t = init;
    }

    operator =(T RHS)
    {
        return t = RHS;
    }
    operator T() const
    {
        return t;
    }
    operator ++()
    {
        return ++t;
    }
    operator ++(int)
    {
        return t++;
    }
    operator +=(T RHS)
    {
        t += RHS;
        return t;
    }
    operator -=(T RHS)
    {
        t -= RHS;
        return t;
    }
    operator *=(T RHS)
    {
        t *= RHS;
        return t;
    }
    operator /=(T RHS)
    {
        t /= RHS;
        return t;
    }

private:
    T t;
};

typedef SmartTypesT<char> stchar;
typedef SmartTypesT<short> stshort;
typedef SmartTypesT<int> stint;
typedef SmartTypesT<long> stlong;
typedef SmartTypesT<float> stfloat;
typedef SmartTypesT<double> stdouble;

Die Anwendung ist jedoch denkbar einfach:

  • Code in eine beliebige Header-Datei kopieren ()
  • Die betreffende Header-Datei an der erforderlichen Stelle einbinden
  • Statt Variable des jeweiligen Basisdatentyps zu deklarieren, den passenden SmartTypeT Typ verwenden
Anwendungsbeispiele:
    SmartTypesT<long> l;
    ATLTRACE(_T("SmartTypesT %d\n"), l);
    SmartTypesT<long> l2 = 10;
    ATLTRACE(_T("SmartTypesT(10) %d\n"), l2);
    stdouble r = 5.5;
    ATLTRACE(_T("stdouble(5.5) %f\n"), r);
Nachteile:

Es darf nicht verschwiegen werden, dass diese Technik einen erheblichen Preis hat: Sie kostet enorme Rechnerleistung. Die Verarbeitung der entsprechenden Variablen war auf meinem System bis zu 30 Mal langsamer als der entsprechende Basisdatentyp. Beispiele:

    long l1;
    for (long c = 0; c < 20000000; c++)
        l1 = c;

    stlong l2;
    for (long c = 0; c < 20000000; c++)
        l2 = c;

Während die erste Schleife nach 62 ms abgearbeitet ist, benötigt die zweite mehr als 1800 ms.

Andererseits: Schleifen mit 20.000.000 Durchläufen sind eher selten. Wenn Sie SmartTypeT für Variablen verwenden, deren Wert sich nur selten ändert, spielt der Leistungsnachteil unter Umständen überhaupt keine Rolle.


* Dieser Spruch ist eigentlich geklaut! Er stammt im Original von Bruce McKinney, Autor des hervorragenden Buches Hardcore Visual Basic.

Die Erlaubnis, den Quellcode zeitlich, räumlich und inhaltlich unbegrenzt zu verwenden wird hiermit erteilt unter der Auflage, dass die Nennung von Ralf Kunsmann als Autor unter Angabe der Web-Adresse www.kunsmann.de im Quellcode erfolgt.

Seitenanfang

Kontaktaufnahme- und Terminvereinbarung:

Bei Fragen und für Terminvereinbarungen erreichen Sie uns unter:

0 63 49 99 07 38

0 151 51 95 34 00

Oder nutzen Sie das Kontaktformular




Ihr Ansprechpartner:


Hier sollte das Fahnungsfoto zu sehen sein.

Ralf Kunsmann

Spezialist für VBA-Programmierung
(alle Office-Anwendungen)
Entwickler der
VBA-Extension-Tools