Wie statischen Zeiger initialisieren

Du bist neu in der Welt von C++? Dann schau hier herein!
Antworten
Bang-Johansen
Beiträge: 43
Registriert: 11. Juli 2011 22:51

Wie statischen Zeiger initialisieren

Beitrag von Bang-Johansen »

Hallo,

ich habe eine Klasse, wo ich in der .h Datei mehrere Variablen statisch deklariert habe.

z.B.

private:
static QString Device,Parity;
static bool RS232IsStarted;

in der .cpp Datei steht ganz am Anfang dann:

// statische Variablen initialisieren
QString rs232::Device = 0;
QString rs232::Parity = 0;
bool rs232::RS232IsStarted= FALSE;

Wie muß ich jetzt einen Zeiger am Anfang in der .cpp Datei initialisieren ?
z.B.
in der .h Datei

// verwendeter Zugriff
static QextSerialPort *Port;

was muß ich dann in der .cpp Datei am Anfag schreiben ??

Danke Euch

Bang-Johansen
Bang-Johansen
Beiträge: 43
Registriert: 11. Juli 2011 22:51

Re: Wie statischen Zeiger initialisieren

Beitrag von Bang-Johansen »

Hallo,

ich habe jetzt folgende Lösung gefunden.

QextSerialPort *rs232::Port = NULL;

Ist diese OK ??

Bang-Johansen
brax
Beiträge: 208
Registriert: 11. Mai 2010 11:22

Re: Wie statischen Zeiger initialisieren

Beitrag von brax »

Grundsätzlich ist das vollkommen OK. Natürlich hast Du damit nur einen NULL-Pointer, bevor Du "Port" also benutzt musst Du auch noch ein entsprechendes Objekt anlegen (aber ich denke mal der Teil ist Dir klar). Daher ein bißchen Info, wie man das am besten macht....

Du das Objekt hinter dem Pointer direkt erzeugen:

Code: Alles auswählen

QextSerialPort* rs232::Port = new QextSerialPort();
// keine Ahnung, was ein QextSerialPort so als Parameter im Konstruktor bekommt...
Wahrscheinlich möchtest Du es nicht so machen, weil der Port wahrscheinlich nicht direkt initialisiert werden kann....

Daher benutzt man in dem Fall idR "lazy initialization", wo da Objekt erst erzeugt wird, wenn man es braucht.
Denkbar ist da die Anwendung des Singleton Patterns:

Code: Alles auswählen

QextSerialPort* rs232::Port = NULL;

// muss im Header als statische Methode deklariert sein
QextSerialPort* rs232::PortInstance() {
    if (!Port) {
        Port = new QextSerialPort();
        // mehr Initialisierung ....
    }
    return Port;
}
Wenn Du dann "Port" benutzen möchtest, benutzt Du nicht direkt die statische Variable sondern die statische Methode "PortInstance". Problem: Das ganze ist nicht thread-safe. Wenn Du aus unterschiedlichen Threads auf das Singleton zugreifen willst, musst Du die Methode per mutex absichern (sonst werden u.U. mehrere Instanzen erzeugt). Das ist extrem teuer, aber kaum zu umgehen (wenn Du googlest und irgendwas zu "Double Checked Locking" findest... vergiss es! :
There are lots of reasons it doesn't work. The first couple of
reasons we'll describe are more obvious. After understanding
those, you may be tempted to try to devise a way to "fix" the
double-checked locking idiom. Your fixes will not work: there
are more subtle reasons why your fix won't work. Understand
those reasons, come up with a better fix, and it still won't
work, because there are even more subtle reasons.
Lots of very smart people have spent lots of time looking at
this. There is no way to make it work without requiring each
thread that accesses the helper object to perform
synchronization.
Wenn Du mehr wissen willst:
http://www.cs.umd.edu/~pugh/java/memory ... cking.html

Daher:
Wenn Du einen C++11 Compiler benutzt (und es gibt [abgesehen von einem sehr langsamen Arbeitgeber] keinen Grund dies nicht zu tun) kannst Du Dir den Mutex sparen und eine der folgenden Lösungen wählen, die laut dem neuen Standard sicher sind:


Die erste Variante ist eigentlich Compilerabhängig, wird aber nach Aussage einer Person, die es wissen muss (er sitzt im C++ Konsortium und ist Berater für die Entwickler vom GCC und vom MS-VC Compiler bezüglich des neuen Standards), von allen Compilern korrekt umgesetzt (d.h. erst beim ersten Aufruf der Methode wird der Konstruktor aufgerufen).

Code: Alles auswählen

QextSerialPort* rs232::PortInstance() {
    static QextSerialPort* port = new QextSerialPort(); // dafür kannst Du auf die statische Klassenvariable verzichten
    return port;
}
Die zweite Variante ist in jedem Fall absolut sicher, hat aber auch zwei Zeilen mehr und eine gewöhnungsbedürftige Syntax (ich hab mich dran gewöhnt... es dauert nicht lange ... und es ist wunderbar!!! ;) )

Code: Alles auswählen

#include <mutex>
QextSerialPort* rs232::PortInstance() {
    static std::once_flag flag;
    static QextSerialPort* port = nullptr; // das gleiche wie NULL, falls Du C++11 noch gar nicht kennst ;)
    std::call_once(flag, [] { port = new QextSerialPort(); } ); // Benutzung eines LAMBDAS... eine der wunderschönen Neuerungen, die der neue Standard gebracht hat. Unbedingt anschauen!!!!
    return port;
}
Der neue Standard hat einige schöne neue Sachen mitgebracht. Daher noch zwei Links:
http://en.wikipedia.org/wiki/C%2B%2B11 Wiki... nicht so spannend, aber doch recht gut
http://channel9.msdn.com/Events/GoingNa ... ative-2012 Sehr empfehlenswert! Um ehrlich zu sein, ist das glatt ein Topic Wert...
Bang-Johansen
Beiträge: 43
Registriert: 11. Juli 2011 22:51

Re: Wie statischen Zeiger initialisieren

Beitrag von Bang-Johansen »

Hallo brax,

erstmal vielen Dank für Deine umfassende und wirklich sehr gute Antwort.

Ich habe es im Moment so gelöst, daß ich einfach in einer Methode das Objekt erzeuge und mit geladenen Parametern konfiguriere.
In einer anderen Methode kann ich dann den Port wieder schließen.
In einer anderen methode kann ich es wie gewünscht umkonfigurieren.

Das Objekt hinter dem Pointer zu erzeugen-> weiß nicht, ob ich das wirklich brauche.

Das mit dem Singleton Pattern hatte ich schon probiert, es hat aber erstmal nicht so funktioniert wie es sollte.
Ich habe da Bildungstechnisch noch einigen Nachholbedarf ;-).
Daher hatte ich mich erst mal für die static Version entschieden.

Vielleicht kann ich auf diese auch verzichten, wenn ich über eine Klasse , die den Port als Objekt dann einbindet,eine Art Durchreiche einrichte, um für eine
dritte Klasse Zugriff auf einige Methoden bekomme.

Dein letztes Beispiel ist wirklich gewöhnungsbedürftig.
Das muß ich mir mal in aller Ruhe anschauen.

Danke

Bang-Johansen
Antworten