Meiner Meinung nach sind die Gefahren von C ++ etwas übertrieben.
Die wesentliche Gefahr ist folgende: Während Sie mit C # "unsichere" Zeigeroperationen mit dem unsafe
Schlüsselwort ausführen können , können Sie mit C ++ (das größtenteils eine Obermenge von C darstellt) Zeiger verwenden, wann immer Sie dies wünschen. Neben den üblichen Gefahren, die mit der Verwendung von Zeigern verbunden sind (die mit C identisch sind), wie Speicherlecks, Pufferüberläufen, baumelnden Zeigern usw., bietet C ++ neue Möglichkeiten, um die Dinge ernsthaft zu vermasseln.
Dieses "zusätzliche Seil", von dem Joel Spolsky sozusagen sprach, beruht im Grunde auf einer Sache: dem Schreiben von Klassen, die intern ihr eigenes Gedächtnis verwalten, auch als " Regel von 3 " bekannt (die jetzt als Regel bezeichnet werden kann) von 4 oder Regel von 5 in C ++ 11). Das heißt, wenn Sie jemals eine Klasse schreiben möchten, die ihre eigenen Speicherzuordnungen intern verwaltet, müssen Sie wissen, was Sie tun, sonst stürzt Ihr Programm wahrscheinlich ab. Sie müssen einen Konstruktor, einen Kopierkonstruktor, einen Destruktor und einen Zuweisungsoperator sorgfältig erstellen, was überraschenderweise leicht zu Fehlern führt und zur Laufzeit oft zu bizarren Abstürzen führt.
JEDOCH in der tatsächlichen täglichen C ++ Programmierung, dann ist es sehr selten in die Tat eine Klasse zu schreiben , die einen eigenen Speicher verwaltet, so dass es irreführend zu sagen , dass C ++ Programmierer immer „vorsichtig“ sein muß , diese Fallen zu vermeiden. Normalerweise machst du einfach so etwas wie:
class Foo
{
public:
Foo(const std::string& s)
: m_first_name(s)
{ }
private:
std::string m_first_name;
};
Diese Klasse ähnelt in etwa Ihren Java- oder C # -Vorgängen. Sie erfordert keine explizite Speicherverwaltung (da die Bibliotheksklasse dies std::string
alles automatisch erledigt), und seit der Standardeinstellung sind überhaupt keine "3er-Regeln" erforderlich Kopierkonstruktor und Zuweisungsoperator sind in Ordnung.
Es ist nur, wenn Sie versuchen, etwas zu tun, wie:
class Foo
{
public:
Foo(const char* s)
{
std::size_t len = std::strlen(s);
m_name = new char[len + 1];
std::strcpy(m_name, s);
}
Foo(const Foo& f); // must implement proper copy constructor
Foo& operator = (const Foo& f); // must implement proper assignment operator
~Foo(); // must free resource in destructor
private:
char* m_name;
};
In diesem Fall kann es für Anfänger schwierig sein, die Zuweisung, den Destruktor und den Kopierkonstruktor korrekt zu machen. In den meisten Fällen gibt es jedoch keinen Grund, dies jemals zu tun. Mit C ++ können Sie die manuelle Speicherverwaltung in 99% der Fälle ganz einfach vermeiden, indem Sie Bibliotheksklassen wie std::string
und verwenden std::vector
.
Ein weiteres verwandtes Problem ist die manuelle Speicherverwaltung, bei der die Möglichkeit, dass eine Ausnahme ausgelöst wird, nicht berücksichtigt wird. Mögen:
char* s = new char[100];
some_function_which_may_throw();
/* ... */
delete[] s;
Wenn some_function_which_may_throw()
tatsächlich nicht eine Ausnahme auslösen, sind Sie mit einem Speicherverlust gelassen , weil der Speicher reserviert für s
nie zurückgewonnen werden. In der Praxis ist dies jedoch kaum noch ein Problem, da die "Regel von 3" kein wirkliches Problem mehr darstellt. Es ist sehr selten (und normalerweise unnötig), sein eigenes Gedächtnis mit rohen Zeigern zu verwalten. Um das obige Problem zu vermeiden, müssen Sie lediglich ein std::string
oder verwenden std::vector
, und der Destruktor wird beim Abwickeln des Stapels nach dem Auslösen der Ausnahme automatisch aufgerufen.
Ein allgemeines Thema hier ist also, dass viele C ++ - Funktionen, die nicht von C geerbt wurden, wie automatische Initialisierung / Zerstörung, Kopierkonstruktoren und Ausnahmen, einen Programmierer dazu zwingen, bei der manuellen Speicherverwaltung in C ++ besonders vorsichtig zu sein. Dies ist jedoch wiederum nur dann ein Problem, wenn Sie zunächst die manuelle Speicherverwaltung durchführen möchten, die bei Standardcontainern und Smart Pointern kaum noch erforderlich ist.
Meiner Meinung nach ist es in C ++ zwar nicht nötig, sich daran aufzuhängen, aber in modernen C ++ sind die Fallstricke, über die Joel sprach, trivial einfach zu vermeiden.
Your questions should be reasonably scoped. If you can imagine an entire book that answers your question, you’re asking too much.
. Ich glaube, dies ist eine solche Frage ...