Der (Nichts-)Datentyp Void
-
aber sit es nicht eigendlich auch ein kleines zeichen für ein eventuell falsches/schlechtes design?
-
Wikinger75 schrieb:
...Aber ich habe auch gehört, bzw gelesen, dass es auch Void-Zeiger gibt, usw.
void* MyVoidPointer;void und void* haben eigentlich nichts miteinander zu tun.
Wikinger75 schrieb:
1.) Was bringt so ein Void Zeiger?
2.) Was gibt er zurück, falls er doch etwas rückgeben kann?
3.) Wozu verwendet man ihn?
4.) Wie verwendet man ihn?Ein void-Zeiger ist ein Zeiger, der keine Informationen darüber hält auf was er zeigt. Im Prinzip kann ein void-Zeiger anstelle eines anderen Zeigers verwendet werden, und wird vorwiegend in C oder altem C++ Code verwendet. Bevor es Templates gab, dienten void-Zeiger z.B. zum Bau generischer Listen, nur das es dann der Anwender dafür sorgen musste, was sich genau dahinter verbirgt, wie es umzuwandeln ist...
Man sollte auch nicht auf die Idee kommen einen void-Zeiger per delete zu löschen, da dem Zeiger wie gesagt auch die Informationen fehlen was sich hinter der Speicheradresse wirklich verbirgt.
In Modernen C++ deutet ein void-Zeiger in der Regel auf schlechtes Design hin, und sollte zumindestens hinter Schnittstellen verborgen werden.
Ich werde absichtlich kein konkretes Anwendungsbeispiel bringen, da es Anfänger meist zu schlechten Code animert.
Wikinger75 schrieb:
1.) Währe auch das hier möglich?
void Var;2.) Falls ja wozu könnte man das verwenden?
3.)Falls ja wie kan man das verwenden?Nein, womit 2 und 3 auch hinfällig werden.
cu André
-
Wikinger75 schrieb:
[..]Ich hab mit der Such-Machiene nichts gefunden[..]
Dann bist du ja fündig geworden. :p (als ich den Satz nachdem Titel gelesen habe, musste ich echt schmunzeln. :))
In Modernen C++ deutet ein void-Zeiger in der Regel auf schlechtes Design hin, und sollte zumindestens hinter Schnittstellen verborgen werden.
Ich werde absichtlich kein konkretes Anwendungsbeispiel bringen, da es Anfänger meist zu schlechten Code animert.
Aber die gute Alternative zeigst du nicht?

In C++ arbeitet, wie schon gesagt eher mit templates und wenn man eine Liste von mehr oder weniger unterschiedlichen Datentypen braucht, welche aber eine gemeinsame Schnittstelle anbieten, dann ist dafür eine gemeinsame abstrakte Basisklasse zu empfehlen. (Auf die kann man dann auch gefahrenlos delete anwenden, sofern der Destruktor der Basisklasse virtuell ist).
-
beispiel:
void ausgeben(void * stuff) // alt... { cout << *stuff << endl; } template<class _T> // neu mit template void ausgeben(_T stuff) { cout << stuff << endl; }so ist das doch oder?
(ich hab selber noch nie mit voidpointern gearbeitet deswegen frag ich)
-
In der WinAPI gibts z.B. die Funktion CreateThread, die einen Thread erzeugt und einen Funktionszeiger übergeben bekommt, dessen Funktion dann ausgeführt wird (als Thread).
CreateThread hat jetzt noch die Möglichkeit, dieser Funktion die sie als Funktionszeiger übergeben bekommt ein gewissen Parameter beim Aufruf "als Thread" mitzugeben. Da man aber nicht weiß, welchen Typ dieser Parameter haben könnte (es soll ja allgemein sein) und es eine C API ist, benutzt man einen void Zeiger.
Die Funktion muss dann ihren übergebenen void Zeiger in den entsprechenden Typ konventieren und hoffen, dass der Typ stimmt, ansonsten gibts einen netten Absturz.
void threadFunktion(void* parameter) { int* data = (int*)parameter. }In C++ würde man allerdings den Cast durch einen reinterpret_cast oder static_cast ersetzten.
int* data = reinterpret_cast<int*>(paramter);In C++ würde man das ganze Problem aber sowieso mit Templates bei CreateThread anstatt void Zeigern lösen, so dass man dann bequem und typsicher schreiben kann:
void threadFunktion(int data) { }In C++ benutzt man eigentlich fast nur dann void Zeiger, wenn man gerade auf C API's zugreift, bzw. diese wrappt.
Falls du das nicht verstehst, schlage CreateThread / wrapper bei Google nach.
Die Motivation bei C++ ist eben weg von dem alten C zu kommen und ein bisschen sauberer zu coden, wie eben in Java. Aber reden wir nicht von Java ...
-
Skym0sh0 schrieb:
so ist das doch oder?
(ich hab selber noch nie mit voidpointern gearbeitet deswegen frag ich)In C wurden halt Funktionspointer als void* übergeben, was in C++ mit Funktoren oder Funktionen geht, da lediglich etwas übergeben werden muss, wo der ()-Operator angewendet werden kann. (Rückgabewert und Parameter müssen nat. auch noch stimmen..).
-
Skym0sh0 schrieb:
beispiel:
void ausgeben(void * stuff) // alt... { cout << *stuff << endl; } template<class _T> // neu mit template void ausgeben(_T stuff) { cout << stuff << endl; }so ist das doch oder?
(ich hab selber noch nie mit voidpointern gearbeitet deswegen frag ich)Bei der C Variante müsstest du den void Zeiger stuff noch gefährlicherweise und unsichererweise und unschönerweise (lol) in einen entsprechenden explizit angegebenen Typ casten.
Der Operator * bei einem ungecastetem void Zeiger ist übrigens so eine Sache... ich meine void kann ja nicht als Datentyp rauskommen, den gibts ja nicht.
Könnte sogar ein Compile-fehler geben.
-
Ja Dnake für eure Antworten^^
Ich wollte den auch nicht benutzen, nur bei paar Bibliotheken aus dem C++ wie in istream und wahrscheinlich auch in anderen streams ein
void&definiert ist, der eine Adresse einlist und in einem Zeiger abspeichert oder bei ostream, da gibts einen void* Zeiger der eine Adresse als hexadezimal ausgibt, allerding wird dieser je nach Typ von ostream verwaltet mit dem << operator aufgerufen...
Ich hab nur nachgefragt was es mit dem nun aufsich hat.
Was ich nun weis und worum ich schlauer geworden bin:^^
void* ist nur wegen Kombitaliltäs-Gründen aus C mitgenommen.
In C++ benutzt man die Templates(Die ich sowieso schon kenne und deren Anwendung) statt des void* da der anfällig für Fehler ist.
void und void* sind zwei verschiedene Dinge.
Void's besitzen keinen rückgabe Typen und man sollte nicht veruschen etwas mit new und delete hinzubekommen.Mehr wollte ich nicht wissen^^.
Danke Leute!PS: Jedoch währe bei der Funktion mit Template doch ein Fehler möglich

template<class T> void function(T Parameter) { cout << Parameter << endl; }Damit könnte man wenn man es beabsichtigt folgendes schreiben, was zu einem Fehler führen würde^^
int main() { void* MyVoidZeiger; function(MyVoidZeiger); }Normaler Weise gebä es hier einen Compiler fehler, oder würde da der Compiler mitmachen?^^
-
Warum sollte das ein Fehler sein? - Du gibst lediglich die Adresse eines Zeigers aus. (Halt auf ein void, aber das ist dem Zeiger egal)
-
Wikinger75 schrieb:
void* ist nur wegen Kombitaliltäs-Gründen aus C mitgenommen.Falsch, void* braucht man u.a. fürs Speichermanagement. operator new gibt z.B. void* zurück.
In C++ benutzt man die Templates(Die ich sowieso schon kenne und deren Anwendung) statt des void* da der anfällig für Fehler ist.Ansichtssache. Es ist eher so, dass man in C keine Templates hat und deshalb Workarounds mit void-Pointern bauen muss

Void's besitzen keinen rückgabe Typen und man sollte nicht veruschen etwas mit new und delete hinzubekommen.Hä?
-
Bei void-Funktionen und Rückgabe ist das so ne Sache. Man könnte sagen, sie geben void zurück, denn sowas ist ja möglich:
void fun1() {} void fun2() { return fun1(); }
-
Bashar schrieb:
Falsch, void* braucht man u.a. fürs Speichermanagement. operator new gibt z.B. void* zurück.
newgibt den einen passenden Pointer-Typen zurück, und kein void*.
-
Wirklich?
Ich finde in 3.7.3 2 nur void* als Rückgabetyp für den globalen operator new.
-
Weil der globale _Operator_ new nur für die Speicherallozierung zuständig ist, die das _Schlüsselwort_ new (Also ein new-Ausruck) benötigt. Tachyon hat also etwas anderes gemeint als Bashar und beide haben Recht

-
Decimad schrieb:
Weil der globale _Operator_ new nur für die Speicherallozierung zuständig ist, die das _Schlüsselwort_ new (Also ein new-Ausruck) benötigt.
falsch.
die operator new gibt einen void* zurück und der operator new gibt einen spezifischen zeiger zurück.(DIE globale funktion namens operator new gibt einen void* zurück. DER globale operator namens operator new gibt einen spezifischen zeiger zurück. der operator new benutzt die operator new, um speicher zu besorgen und ruft dann den konstruktor auf und gibt den vollkonstruierten speicher zurück.)
-
volkard schrieb:
(DIE globale funktion namens operator new gibt einen void* zurück. DER globale operator namens operator new gibt einen spezifischen zeiger zurück. der operator new benutzt die operator new, um speicher zu besorgen und ruft dann den konstruktor auf und gibt den vollkonstruierten speicher zurück.)
Naja, ganz klar ist das auch nicht, zumal Operatoren auch Funktionen sind.

Aber ich denke, wir wissen alle, was gemeint ist...

T* Ptr = new T; // new-Operator -> T* void* Mem = operator new(sizeof(T)); // operator new -> void*
-
Nexus schrieb:
Naja, ganz klar ist das auch nicht, zumal Operatoren auch Funktionen sind.

falsch. der operator new und der operator sizeof verarbeiten einen typen, das können funktionen nicht.
T* Ptr = new T; // new-Operator -> T* void* Mem = operator new(sizeof(T)); // operator new -> void*aber "new-Operator" und "operator new" sind keine guten unterscheidungen, zumal der "new-Operator" den in c++ namen "operator new" trägt.
-
volkard schrieb:
der operator new und der operator sizeof verarbeiten einen typen, das können funktionen nicht.
Stimmt schon. Trotzdem finde ich die Unterscheidung nur auf Grund des Artikels fragwürdig. Operatoren sind schlussendlich beides...
Am klarsten ist es wohl, wenn man einfach nur
newrespektiveoperator newsagt.
-
Nexus schrieb:
volkard schrieb:
der operator new und der operator sizeof verarbeiten einen typen, das können funktionen nicht.
Stimmt schon. Trotzdem finde ich die Unterscheidung nur auf Grund des Artikels fragwürdig. Operatoren sind schlussendlich beides...
Warum das denn?
Ist printf() ein Operator? Wäre mir neu. Und genausowenig ist die Funktion operator new ein Operator.Am klarsten ist es wohl, wenn man einfach nur
newrespektiveoperator newsagt.aber beide heißen
operator newdas ist fakt. eure unterscheidungen sind erfunden.
wenn du es klar machen willst, sag bei der funktion immer "Funktion" dazu und beim operator immer "Operator". ausnahmsweise ien grund für großschrift.
also
- die Funktion operator new
- der Operator operator newaber bereits
- die Funktion new
- der Operator new
wird mißverstanden.
-
volkard schrieb:
Am klarsten ist es wohl, wenn man einfach nur
newrespektiveoperator newsagt.aber beide heißen
operator newdas ist fakt. eure unterscheidungen sind erfunden.
Der Operator
newheißtoperator new? In welchem Kontext?