À mon avis, les dangers du C ++ sont quelque peu exagérés.
Le danger essentiel est le suivant: tandis que C # vous permet d'effectuer des opérations de pointeur «non sécurisées» à l'aide de la commande unsafe
mot clé, C ++ (étant principalement un surensemble de C) vous permettra d'utiliser des pointeurs chaque fois que vous en aurez envie. Outre les dangers habituels inhérents à l'utilisation de pointeurs (qui sont les mêmes avec C), comme les fuites de mémoire, les débordements de tampon, les pointeurs pendants, etc., C ++ introduit de nouvelles façons pour vous de sérieusement bousiller les choses.
Cette "corde supplémentaire", pour ainsi dire, dont parlait Joel Spolsky , se résume essentiellement à une chose: écrire des cours qui gèrent en interne leur propre mémoire, également connue sous le nom de " Règle de 3 " (qui peut maintenant être appelée la Règle de 4 ou règle de 5 en C ++ 11). Cela signifie que si vous souhaitez écrire une classe qui gère ses propres allocations de mémoire en interne, vous devez savoir ce que vous faites, sinon votre programme se bloquera probablement. Vous devez soigneusement créer un constructeur, un constructeur de copie, un destructeur et un opérateur d'affectation, ce qui est étonnamment facile à se tromper, ce qui entraîne souvent des plantages bizarres lors de l'exécution.
TOUTEFOIS , dans la programmation C ++ quotidienne réelle, il est très rare d'écrire une classe qui gère sa propre mémoire, il est donc trompeur de dire que les programmeurs C ++ doivent toujours être "prudents" pour éviter ces pièges. Habituellement, vous ferez simplement quelque chose de plus comme:
class Foo
{
public:
Foo(const std::string& s)
: m_first_name(s)
{ }
private:
std::string m_first_name;
};
Cette classe ressemble assez à ce que vous feriez en Java ou en C # - elle ne nécessite aucune gestion de mémoire explicite (car la classe de bibliothèque std::string
s'occupe de tout cela automatiquement), et aucune substance "Rule of 3" n'est requise du tout depuis la valeur par défaut constructeur de copie et opérateur d'affectation est très bien.
Ce n'est que lorsque vous essayez de faire quelque chose comme:
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;
};
Dans ce cas, il peut être difficile pour les novices de corriger l'affectation, le destructeur et le constructeur de copie. Mais pour la plupart des cas, il n'y a aucune raison de le faire. C ++ permet d'éviter très facilement la gestion manuelle de la mémoire 99% du temps en utilisant des classes de bibliothèque comme std::string
et std::vector
.
Un autre problème connexe est la gestion manuelle de la mémoire d'une manière qui ne prend pas en compte la possibilité d'une exception levée. Comme:
char* s = new char[100];
some_function_which_may_throw();
/* ... */
delete[] s;
Si en some_function_which_may_throw()
fait ne jette une exception, vous vous retrouvez avec une fuite de mémoire car la mémoire allouée s
ne sera jamais récupéré. Mais encore une fois, dans la pratique, ce n'est plus un problème pour la même raison que la «règle de 3» n'est plus vraiment un problème. Il est très rare (et généralement inutile) de gérer réellement votre propre mémoire avec des pointeurs bruts. Pour éviter le problème ci-dessus, tout ce que vous devez faire est d'utiliser un std::string
ou std::vector
, et le destructeur sera automatiquement invoqué lors du déroulement de la pile après la levée de l'exception.
Ainsi, un thème général ici est que de nombreuses fonctionnalités C ++ qui n'ont pas été héritées de C, telles que l'initialisation / destruction automatique, les constructeurs de copie et les exceptions, obligent un programmeur à être extrêmement prudent lors de la gestion manuelle de la mémoire en C ++. Mais encore une fois, ce n'est un problème que si vous avez l'intention de faire une gestion manuelle de la mémoire en premier lieu, ce qui n'est presque plus nécessaire lorsque vous avez des conteneurs standard et des pointeurs intelligents.
Donc, à mon avis, alors que le C ++ vous donne beaucoup de corde supplémentaire, il n'est presque jamais nécessaire de l'utiliser pour vous accrocher, et les pièges dont Joel parlait sont trivialement faciles à éviter dans le C ++ moderne.
Your questions should be reasonably scoped. If you can imagine an entire book that answers your question, you’re asking too much.
. Je crois que cela se qualifie comme une telle question ...