it-swarm.com.de

Warum werden "void *" nicht implizit in C ++ umgewandelt?

In C muss kein void * zu jedem anderen Zeigertyp wird immer sicher heraufgestuft. In C++ ist dies jedoch nicht der Fall. Z.B.,

int *a = malloc(sizeof(int));

funktioniert in C, aber nicht in C++. (Hinweis: Ich weiß, dass Sie malloc in C++ oder new nicht verwenden sollten und stattdessen intelligente Zeiger und/oder die STL bevorzugen sollten. Dies wird nur aus Neugier gefragt ) Warum erlaubt der C++ - Standard diese implizite Umwandlung nicht, während der C-Standard dies tut?

30
wolfPack88

Da implizite Typkonvertierungen normalerweise unsicher sind und C++ beim Tippen sicherer ist als C.

C erlaubt normalerweise implizite Konvertierungen, auch wenn die meisten Chancen bestehen, dass die Konvertierung ein Fehler ist. Das liegt daran, dass C davon ausgeht, dass der Programmierer genau weiß, was er tut, und wenn nicht, ist es das Problem des Programmierers, nicht das Problem des Compilers.

C++ verbietet normalerweise Dinge, die möglicherweise Fehler sein könnten, und erfordert, dass Sie Ihre Absicht explizit mit einer Typumwandlung angeben. Das liegt daran, dass C++ versucht, programmiererfreundlich zu sein.

Sie könnten fragen, warum es freundlich ist, wenn Sie tatsächlich mehr eingeben müssen.

Nun, Sie sehen, jede gegebene Codezeile, in jedem Programm, in jeder Programmiersprache wird im Allgemeinen viel öfter gelesen als geschrieben (*). Die Leichtigkeit des Lesens ist daher viel wichtiger als die Leichtigkeit des Schreibens. Und beim Lesen hilft es, potenziell unsichere Conversions durch explizite Typumwandlungen hervorzuheben, um zu verstehen, was vor sich geht, und um ein gewisses Maß an Sicherheit zu haben, dass das, was passiert, tatsächlich das ist, was passieren sollte.

Außerdem ist die Unannehmlichkeit, die explizite Besetzung eingeben zu müssen, trivial im Vergleich zu der Unannehmlichkeit, stundenlang Fehler zu beheben, um einen Fehler zu finden, der durch eine fehlerhafte Zuordnung verursacht wurde, vor der Sie hätten gewarnt werden können, die Sie aber nie waren.

(*) Idealerweise wird es nur einmal geschrieben, aber es wird jedes Mal gelesen, wenn jemand es überprüfen muss, um festzustellen, ob es für die Wiederverwendung geeignet ist, und jedes Mal, wenn eine Fehlerbehebung durchgeführt wird und jedes Mal, wenn jemand Code in der Nähe hinzufügen muss. und dann jedes Mal, wenn Fehler in der Nähe behoben werden, und so weiter. Dies gilt in allen Fällen, mit Ausnahme von Skripten, die einmal geschrieben, ausgeführt und dann weggeworfen wurden. Daher ist es kein Wunder, dass die meisten Skriptsprachen eine Syntax haben, die das Schreiben erleichtert, wobei das Lesen völlig außer Acht gelassen wird. Haben Sie jemals gedacht, dass Perl völlig unverständlich ist? Du bist nicht alleine. Stellen Sie sich solche Sprachen als "Nur-Schreiben" -Sprachen vor.

39
Mike Nakis

Hier ist was Stroustrup sagt :

In C können Sie implizit eine Leere * in ein T * konvertieren. Das ist unsicher

Anschließend zeigt er ein Beispiel dafür, wie gefährlich void * sein kann, und sagt:

... Folglich benötigen Sie in C++ eine explizite Besetzung, um ein T * aus einer Leere * zu erhalten. ...

Schließlich stellt er fest:

Eine der häufigsten Anwendungen dieser unsicheren Konvertierung in C besteht darin, das Ergebnis von malloc () einem geeigneten Zeiger zuzuweisen. Zum Beispiel:

int * p = malloc (sizeof (int));

Verwenden Sie in C++ den typsicheren neuen Operator:

int * p = new int;

Er geht in Das Design und die Entwicklung von C++ viel detaillierter darauf ein.

Die Antwort lautet also: Der Sprachdesigner glaubt, dass es sich um ein unsicheres Muster handelt, und machte es daher illegal und bot alternative Möglichkeiten, um das zu erreichen, wofür das Muster normalerweise verwendet wurde.

28
Gort the Robot

In C ist es nicht erforderlich, eine Leere * in einen anderen Zeigertyp umzuwandeln. Sie wird immer sicher heraufgestuft.

Es wird immer beworben, ja, aber kaum sicher.

C++ deaktiviert dieses Verhalten genau deshalb, weil es versucht, ein sichereres Typsystem als C zu haben, und dieses Verhalten ist nicht sicher.


Betrachten Sie im Allgemeinen diese drei Ansätze zur Typkonvertierung:

  1. zwingen Sie den Benutzer, alles aufzuschreiben, damit alle Konvertierungen explizit sind
  2. angenommen, der Benutzer weiß, was er tut, und konvertiert einen beliebigen Typ in einen anderen
  3. implementieren Sie ein vollständiges Typsystem mit typsicheren Generika (Vorlagen, neue Ausdrücke), expliziten benutzerdefinierten Konvertierungsoperatoren und erzwingen Sie explizite Konvertierungen nur für Dinge, die der Compiler nicht sehen kann

Nun, ich bin hässlich und ein praktisches Hindernis, um etwas zu erledigen, könnte aber wirklich dort eingesetzt werden, wo große Sorgfalt erforderlich ist. C entschied sich grob für 2, das einfacher zu implementieren ist, und C++ für 3, das schwieriger zu implementieren, aber sicherer ist.

11
Useless

Per Definition kann ein ungültiger Zeiger auf alles zeigen. Jeder Zeiger kann in einen ungültigen Zeiger konvertiert werden. Auf diese Weise können Sie den genau gleichen Wert zurückkonvertieren. Zeiger auf andere Typen können jedoch Einschränkungen aufweisen, z. B. Ausrichtungsbeschränkungen. Stellen Sie sich beispielsweise eine Architektur vor, in der Zeichen eine beliebige Speicheradresse belegen können, Ganzzahlen jedoch an geraden Adressgrenzen beginnen müssen. In bestimmten Architekturen können ganzzahlige Zeiger sogar 16, 32 oder 64 Bit gleichzeitig zählen, sodass ein Zeichen * tatsächlich ein Vielfaches des numerischen Werts von int * hat, während es auf dieselbe Stelle im Speicher zeigt. In diesem Fall würde das Konvertieren von einem Hohlraum * tatsächlich Bits abrunden, die nicht wiederhergestellt werden können und daher nicht umkehrbar sind.

Einfach ausgedrückt kann der leere Zeiger auf alles zeigen, einschließlich auf Dinge, auf die andere Zeiger möglicherweise nicht zeigen können. Somit ist die Konvertierung in den Void-Zeiger sicher, aber nicht umgekehrt.

1
roserez