A mio avviso, i pericoli del C ++ sono in qualche modo esagerati.
Il pericolo essenziale è questo: Mentre C # ti consente di eseguire operazioni di puntatore "non sicure" usando la unsafe
parola chiave, C ++ (essendo principalmente un superset di C) ti permetterà di usare i puntatori ogni volta che ne hai voglia. Oltre ai soliti pericoli insiti nell'uso dei puntatori (che sono gli stessi con C), come perdite di memoria, buffer overflow, puntatori penzolanti, ecc., C ++ introduce nuovi modi per rovinare seriamente le cose.
Questa "corda extra", per così dire, di cui parlava Joel Spolsky , si riduce sostanzialmente a una cosa: scrivere classi che gestiscono internamente la propria memoria, nota anche come " Regola del 3 " (che ora può essere chiamata la Regola di 4 o regola di 5 in C ++ 11). Ciò significa che, se mai vuoi scrivere una classe che gestisca le proprie allocazioni di memoria internamente, devi sapere cosa stai facendo altrimenti il tuo programma probabilmente andrà in crash. Devi creare con cura un costruttore, un costruttore di copia, un distruttore e un operatore di assegnazione, che è sorprendentemente facile sbagliare, causando spesso bizzarri arresti in fase di esecuzione.
TUTTAVIA , nella reale programmazione C ++ quotidiana, è davvero raro scrivere una classe che gestisca la propria memoria, quindi è fuorviante dire che i programmatori C ++ devono sempre essere "attenti" per evitare queste insidie. Di solito, farai solo qualcosa di più simile a:
class Foo
{
public:
Foo(const std::string& s)
: m_first_name(s)
{ }
private:
std::string m_first_name;
};
Questa classe sembra molto simile a ciò che faresti in Java o in C # - non richiede una gestione esplicita della memoria (perché la classe della libreria std::string
si occupa di tutto ciò automaticamente) e non è richiesta alcuna roba "Regola di 3" poiché l'impostazione predefinita costruttore di copia e operatore di assegnazione va bene.
È solo quando provi a fare qualcosa del genere:
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 questo caso, può essere complicato per i principianti ottenere correttamente l'incarico, il distruttore e il costruttore di copie. Ma per la maggior parte dei casi, non c'è motivo di farlo. Il C ++ rende molto semplice evitare la gestione manuale della memoria il 99% delle volte usando classi di librerie come std::string
e std::vector
.
Un altro problema correlato è la gestione manuale della memoria in un modo che non tiene conto della possibilità di generare un'eccezione. Piace:
char* s = new char[100];
some_function_which_may_throw();
/* ... */
delete[] s;
Se some_function_which_may_throw()
in realtà non un'eccezione, si è lasciato con una perdita di memoria, perché la memoria allocata per s
non sarà mai recuperato. Ma di nuovo, in pratica, questo non è più un problema per lo stesso motivo per cui la "Regola del 3" non è più un problema. È molto raro (e di solito non necessario) gestire effettivamente la propria memoria con puntatori non elaborati. Per evitare il problema sopra, tutto ciò che dovresti fare è usare un std::string
o std::vector
, e il distruttore verrebbe automaticamente invocato durante lo svolgimento dello stack dopo che l'eccezione è stata lanciata.
Quindi, un tema generale qui è che molte funzionalità di C ++ che non sono state ereditate da C, come l'inizializzazione / distruzione automatica, i costruttori di copie e le eccezioni, costringono un programmatore a prestare particolare attenzione durante la gestione manuale della memoria in C ++. Ma ancora una volta, questo è solo un problema se si intende in primo luogo eseguire la gestione manuale della memoria, che non è quasi mai più necessaria quando si hanno contenitori standard e puntatori intelligenti.
Quindi, secondo me, mentre il C ++ ti dà molta corda in più, non è quasi mai necessario usarlo per impiccarti, e le insidie di cui parlava Joel sono banalmente facili da evitare nel C ++ moderno.
Your questions should be reasonably scoped. If you can imagine an entire book that answers your question, you’re asking too much.
. Credo che ciò si qualifichi come una domanda del genere ...