Comment passer au C ++ 11?

35

Je suis en train de programmer en C ++ depuis un moment, mais je me concentre principalement sur les fonctionnalités de bas niveau du C ++. Par cela, je veux dire principalement travailler avec des pointeurs et des tableaux bruts. Je pense que ce comportement est connu comme utilisant C ++ en tant que C avec des classes. Malgré cela, je n’ai essayé le C que récemment pour la première fois. J'ai été agréablement surpris de voir comment des langages tels que C # et Java masquent ces détails dans des classes de bibliothèques standard pratiques telles que Dictionnaires et Listes.

Je suis conscient que la bibliothèque standard C ++ contient de nombreux conteneurs tels que des vecteurs, des cartes et des chaînes. C ++ 11 ne fait qu'ajouter à cela en proposant std :: array et des boucles à distance.

Comment apprendre à utiliser au mieux ces fonctionnalités du langage moderne et celles qui conviennent à quels moments? Est-il exact que de nos jours, l'ingénierie logicielle en C ++ est pratiquement dépourvue de gestion manuelle de la mémoire?

Enfin, quel compilateur devrais-je utiliser pour tirer le meilleur parti de la nouvelle norme? Visual Studio possède d’excellents outils de débogage, mais même VS2012 semble avoir un support C ++ 11 terrible.

Survol
la source
2
Je dirais qu'appeler le support C ++ 11 de VS2012 "terrible" est un peu exagéré, mais il pourrait certainement être meilleur (le manque de listes d'initialiseurs est particulièrement gênant pour le code test / jouet). Mais notez qu'ils ont annoncé qu'ils enverraient des mises à jour de compilateur indépendamment du reste de VS, alors je suppose que nous pouvons espérer quelques fonctionnalités C ++ 11 dans VS2012 au cours de l'année 2013.
Martin Ba
3
Au début, je pensais que suggérer l’apprentissage du C ++ 11 serait étrange, mais voir que vous êtes toujours bloqué dans le monde des C-With-Classes ... Il ya une décennie, j’ai lu le C ++ accéléré de Koenig / Moo . Au moment où je faisais déjà déjà de la méta-programmation de modèles (je ne l'ai lue que pour une relecture), cela me semblait quand même une révélation. Depuis, je l'utilise comme base pour enseigner le C ++. Venant de C avec Classes , le livre peut vous montrer un tout nouveau langage que vous ne saviez pas que vous aviez à votre disposition. Cela ne fait que 250 pages et vous pouvez alors passer rapidement à quelque chose de spécifique à C ++ 11, mais IMO est une étape intéressante.
sbi
4
g++ -std=c++11
fredoverflow

Réponses:

50

Tout d'abord, quelques règles de base:

  • Utilisez-le std::unique_ptrcomme pointeur intelligent sans surcharge. Vous ne devriez pas avoir à vous embêter avec des pointeurs bruts très souvent. std::shared_ptrest également inutile dans la plupart des cas. Le désir de propriété partagée trahit souvent un manque de réflexion sur la propriété en premier lieu.

  • Utilisez std::arrayce paramètre pour les tableaux de longueur statique et std::vectorpour les dynamiques.

  • Utilisez intensivement des algorithmes génériques, en particulier:

    • <algorithm>
    • <numeric>
    • <iterator>
    • <functional>
  • Utiliser autoet decltype()partout où ils bénéficient de lisibilité. En particulier, lorsque vous souhaitez déclarer une chose, mais d'un type qui vous importe peu, tel qu'un type d'itérateur ou de modèle complexe, utilisez auto. Lorsque vous voulez déclarer une chose en fonction du type d’autre chose, utilisez decltype().

  • Sécurisez les choses quand vous le pouvez. Lorsque vous avez des assertions qui appliquent des invariants sur un type particulier de choses, cette logique peut être centralisée dans un type. Et cela n’entraîne pas nécessairement de frais généraux d’exécution. Il va sans dire que les conversions de style C ( (T)x) doivent être évitées au profit de préfigurations plus explicites (et consultables!) (Par exemple, de type C ++ static_cast).

  • Enfin, sachez comment la règle de trois:

    • Destructeur
    • Copier le constructeur
    • Opérateur d'assignation

    Est devenue la règle de cinq avec l'ajout du constructeur de déplacement et de l'opérateur d'affectation de déplacement. Et comprendre les références rvalue en général et comment éviter de copier.

C ++ est un langage complexe, il est donc difficile de caractériser la meilleure façon d'utiliser l' ensemble de celui - ci. Mais les pratiques d'un bon développement C ++ n'ont pas fondamentalement changé avec C ++ 11. Vous devez toujours préférer les conteneurs gérés par la mémoire à la gestion manuelle de la mémoire - les pointeurs intelligents facilitent cette tâche.

Je dirais que le C ++ moderne est en effet essentiellement exempt de gestion de mémoire manuelle. L'avantage du modèle de mémoire du C ++ est qu'il est déterministe , et non manuel. Les désallocations prévisibles permettent des performances plus prévisibles.

En ce qui concerne un compilateur, G ++ et Clang sont à la fois compétitifs en termes de fonctionnalités C ++ 11 et en rattrapant rapidement leurs lacunes. Je n'utilise pas Visual Studio, je ne peux donc parler ni pour ni contre.

Enfin, une note sur std::for_each: évitez-le en général.

transform, accumulateEt erase- remove_ifsont bon vieux fonctionnels map, foldet filter. Mais for_eachest plus général et donc moins significatif - il n’exprime aucune intention autre que la boucle. En outre, il est utilisé dans les mêmes situations que celles basées sur les plages foret est syntaxiquement plus lourd, même lorsqu'il est utilisé sans aucun point. Considérer:

for (const auto i : container)
    std::cout << i << '\n';

std::for_each(container.begin(), container.end(), [](int i) {
    std::cout << i << '\n';
});

for (const auto i : container)
    frobnicate(i);

std::for_each(container.begin(), container.end(), frobnicate);
Jon Purdy
la source
6
Existe-t-il des principes contraignants pour ces règles empiriques? Cela semble être une belle liste de suggestions, mais ... en tant qu'étranger arrivant à cette question via Google, en quoi votre réponse m'aidera-t-elle à maîtriser le C ++ 11 de manière raisonnée et à l'utiliser sans m'enrouler autour de l'axe C ++ ?
Robert Harvey
3
+1 pour la liste, mais j'ai un petit nitpick: quand (à juste titre) mettre en garde contre std::for_eachj'aurais prévu la plage basée sur la boucle comme un meilleur remplacement que simple for.
Fabio Fracassi
@FabioFracassi: Oups. J'ai écrit clairement pour contraster avec std::for_each, pas avec la gamme . Je l'ai enlevé pour éviter toute confusion.
Jon Purdy
1
Je mettrais à jour si ce n'était pas pour std::for_each(). Quand vous avez du lambda, c'est certainement mieux qu'une forboucle classique . Avec une forboucle basée sur une plage, ce n'est peut-être pas le cas, mais vous n'avez pas écrit " forboucle basée sur une plage ".
sbi
@sbi: Dans mon esprit, le terme « forboucle» inclut « forboucle basée sur la portée ». J'ai édité avec plus d'explications et un exemple pour clarifier, merci.
Jon Purdy
12

Comme point de départ:

  • Arrêtez d'utiliser char*pour les chaînes. Utilisez std::stringou std::wstringet regardez simplement votre code devenir plus court, plus lisible et plus sûr
  • Arrêtez d'utiliser des tableaux de style C (éléments déclarés avec [ ]) et utilisez std::vectorou toute autre classe de conteneur appropriée. Les bonnes choses à propos destd::vector c’est qu’elle connaît sa propre longueur, qu’elle nettoie son contenu quand elle sort du cadre, qu’elle est facile à itérer et qu’elle s’agrandit lorsque vous ajoutez plus d’articles. Mais il existe d’autres collections qui pourraient fonctionner encore mieux dans votre cas.
  • Utilisez std::unique_ptr- et apprenez std::movepresque immédiatement. Étant donné que cela peut donner lieu à des objets noncopyable, la paresse vous pouvez envoyer de temps en temps vers std::shared_ptr- et vous pouvez avoir des cas véritables d'utilisation pour std::shared_ptrainsi
  • À utiliser autolorsque vous déclarez des itérateurs et des types qui dépendent de déclarations antérieures (par exemple, vous avez précédemment déclaré un vecteur de quelque chose, maintenant vous déclarez quelque chose, utilisez-le auto)
  • Utilisez des algorithmes et for_eachsur un "raw for" chaque fois que vous le pouvez, cela évite aux autres lecteurs de lire votre boucle avec soin pour en conclure que vous êtes en train d'itérer sur l'ensemble de la collection, etc. Si votre compilateur prend en charge "range for", utilisez-le for_each. Apprenez les appels algorithme triviales comme iota, generate, accumulate, find_ifet ainsi de suite.
  • Utilisez les lambdas - ils constituent un moyen simple de tirer parti des algorithmes. Ils ouvrent également la porte à beaucoup plus.

Ne vous énervez pas trop sur le compilateur à utiliser. Le manque "terrible, affreux" de prise en charge de C ++ 11 dans VS2012 réside dans le fait qu'il n'y a pas de modèles variadiques (oui, vous étiez sur le point d'utiliser des modèles variadiques) et que l' {}initialiseur n'existe pas. Je le veux aussi mais je vais à peine arrêter d'utiliser un outil de développement utile.

La deuxième chose à faire, après avoir embrassé std::, est de commencer à penser à RAII. Chaque fois que vous avez

  • action de départ
  • série d'actions avec quelque chose que vous avez obtenu en partant de l'action
  • action de nettoyage qui doit se produire même dans le cas d'exceptions

Vous avez alors un constructeur, un certain nombre de fonctions membres et un destructeur. Ecrivez un cours qui s’occupe de cela pour vous. Vous pourriez même pas avoir à écrire le ctor et le dtor. L'inclusion shared_ptrd'une variable en tant que membre d'une classe est un exemple de code RAII. Vous n'écrivez pas de code de gestion de la mémoire, mais lorsque votre instance sort de son périmètre, les choses se passent bien. Développez cette réflexion pour couvrir des éléments tels que la fermeture de fichiers, la libération de poignées, de verrous, etc. et le code deviendra simplement plus simple et plus petit (tout en éliminant les fuites) sous vos yeux.

Si vous vous sentez vraiment en confiance, éliminez-vous printfen faveur de cout, supprimez les macros #defineet commencez à apprendre quelques "idiomes avancés" comme PIMPL. J'ai tout un cours sur ce sujet chez Pluralsight que vous pouvez probablement visionner avec leur essai gratuit.

Kate Gregory
la source
2
J'aime le fait que vous soyez sarcastique de ne pas utiliser de modèles variadiques de sitôt, mais je pense que le manque d'initialisation d'uniforme manque quelque chose de vraiment important pour la programmation quotidienne.
sbi
Je ne peux pas attendre pour les listes d'initialisateurs ... attendre de savoir quand nous les aurons ...
Kate Gregory
Un autre manque important dans VS2012 est "rvalue references v3", c’est-à-dire le constructeur de déplacement généré automatiquement et move assign.
C64
3

Comment apprendre à utiliser au mieux ces fonctionnalités du langage moderne et celles qui conviennent à quels moments?

En programmant. L'expérience est la meilleure façon d'apprendre.

C ++ 11 comporte de nombreuses nouvelles fonctionnalités (auto, rvalue, nouveaux pointeurs intelligents, pour n'en nommer que quelques-unes). Le mieux est de commencer à les utiliser et à les consulter chaque fois que vous le pouvez et chaque fois que vous trouvez un article intéressant.

Est-il exact que de nos jours, l'ingénierie logicielle en C ++ est pratiquement dépourvue de gestion manuelle de la mémoire?

Cela dépend de ce que vous devez faire. La plupart des applications peuvent se passer de pointeurs intelligents et oublier la gestion de la mémoire. Il reste encore des applications qui ne peuvent pas s’échapper aussi facilement (par exemple, si elles ont besoin d’un nouvel emplacement ou d’un allocateur de mémoire personnalisé pour une raison quelconque).

Si vous devez utiliser Qt, vous devrez utiliser leurs règles pour la gestion de la mémoire.

Quel compilateur devrais-je utiliser pour tirer le meilleur parti de la nouvelle norme?

Tout ce que vous avez sous la main qui supporte le dernier standard:

mais aucun compilateur ne supporte toutes les fonctionnalités.

BЈовић
la source
-7

Mon université utilise encore le C ++ pour enseigner. J'ai programmé avec C ++ pendant 5 ans et maintenant je suis un étudiant diplômé. Bien sûr, maintenant, j'utilise beaucoup Java, Ruby, etc. Je vous recommande vivement de ne pas vous hâter au sujet de ces fonctionnalités dans un langage comme Java. D'après mon expérience et mon opinion, après les fonctionnalités de bas niveau du C ++. Vous devriez vous pencher sur des sujets tels que la programmation générique avec C / C ++, comme la création de classe de modèle, les fonctions de modèle, le remplacement d'opérateur, les méthodes virtuelles, les pointeurs intelligents. Pour la pièce de conception orientée objet, il existe de nombreuses fonctionnalités que C ++ possède et que Java n’a pas, comme le multi-héritage. L'héritage est puissant mais dangereux aussi. Le niveau d'implémentation de la conception orientée objet en C ++ est également un bon sujet. La communication inter-processus, les threads, sont également importants en C ++.

Pour le compilateur et le débogueur. Je sais que Visual Studio est génial. Mais je vous recommande vraiment d'apprendre GDB, Valgrind et Make still, et d'être bon avec ces outils. Microsoft est génial, mais il a fait trop de choses pour vous. En tant qu'étudiant, vous devez vraiment apprendre ces choses que Microsoft a faites vous aussi. Pour le compilateur, G ++ est une bonne chose de GNU.

Après tout, après tant d’années, j’ai vraiment le sentiment que les fonctionnalités les plus importantes sont les fonctionnalités de bas niveau telles que la matrice brute. Le vecteur est vraiment juste un tableau dynamique. Ce sont mes recommandations, quelque chose peut-être trop subjectif, prenez ce que vous pensez être juste.

Sen Han
la source
6
Comment cela répond-il à la question? La question ne concerne pas l’apprentissage de C ++ en général, mais le passage à C ++ 11.
Roc Martí