En prévision du début du cours, "C ++ Developer" a préparé une traduction de matériel intéressant.
Marielle Frank et Sonny Lee, auteurs du cours Learn C ++ sur Codecademy, ont rĂ©cemment eu l'occasion d'interviewer le Dr Bjorn Straustrup, le crĂ©ateur de C ++.Dans le cadre de cette interview, il a rĂ©pondu aux questions C ++ qui ont recueilli le plus de votes sur Stack Overflow.Bien que toutes les interviews valent la peine d'ĂȘtre lues, Codecademy nous a gĂ©nĂ©reusement permis d'en partager une partie.Si vous vous ĂȘtes dĂ©jĂ demandĂ© s'il y avait des rĂ©ponses dĂ©finitivement complĂštes sur Stack Overflow, alors voici quelque chose de plus proche que vous pouvez obtenir Ă coup sĂ»r (bien que nous nous attendions Ă ce que quelqu'un ne soit pas d'accord).Pourquoi le traitement d'un tableau triĂ© est-il plus rapide que le traitement d'un tableau non triĂ©?
Remarque: Cette question est le numéro 1 qui a reçu le plus de votes sur le débordement de pile de tous les temps.
Cela ressemble à une question d'une interview. C'est vrai? Comment saviez-vous que? Il est mauvais de répondre à des questions sur l'efficacité sans prendre de mesures préliminaires, il est donc important de savoir comment les mesurer.J'ai donc vérifié un vecteur d'un million d'entiers et obtenu: 32995
125944
18610
133304
17942
107858
J'ai couru cela plusieurs fois pour m'en assurer. Oui, ce phénomÚne est réel. Mon code principal était:void run(vector<int>& v, const string& label)
{
auto t0 = system_clock::now();
sort(v.begin(), v.end());
auto t1 = system_clock::now();
cout << label
<< duration_cast<microseconds>(t1 â t0).count()
<< " milliseconds\n";
}
void tst()
{
vector<int> v(1'000'000);
iota(v.begin(), v.end(), 0);
run(v, "already sorted ");
std::shuffle(v.begin(), v.end(), std::mt19937{ std::random_device{}() });
run(v, "shuffled ");
}
Au moins, ce phĂ©nomĂšne est rĂ©el avec ce compilateur, la bibliothĂšque standard et les paramĂštres d'optimisation. DiffĂ©rentes implĂ©mentations peuvent donner (et donner) des rĂ©ponses diffĂ©rentes. En fait, quelqu'un a fait une Ă©tude plus systĂ©matique (une recherche rapide sur Internet vous aidera Ă le trouver), et la plupart des implĂ©mentations montrent cet effet.L'une des raisons est la prĂ©diction de branche: l'opĂ©ration clĂ© dans l'algorithme de tri est «if (v [i] <pivot]) ...» ou l'Ă©quivalent. Pour une sĂ©quence triĂ©e, ce test est toujours vrai, tandis que pour une sĂ©quence alĂ©atoire, la branche sĂ©lectionnĂ©e change de façon alĂ©atoire.Une autre raison est que lorsque le vecteur est dĂ©jĂ triĂ©, nous n'avons jamais besoin de dĂ©placer les Ă©lĂ©ments Ă la bonne position. L'effet de ces petits dĂ©tails donne un facteur d'environ cinq ou six, ce que nous avons observĂ©.Quicksort (et le tri en gĂ©nĂ©ral) est une Ă©tude complexe qui a attirĂ© certains des plus grands esprits de l'informatique. Une bonne fonction de tri est le rĂ©sultat du choix d'un bon algorithme et de l'attention portĂ©e aux performances de l'Ă©quipement lors de sa mise en Ćuvre.Si vous voulez Ă©crire du code efficace, vous devez prendre en compte l'architecture de la machine.âââââââââââââââââââââââââââââDĂ©solĂ© pour l'intervention. Juste un rappel que le podcast Stack Overflow est de retour! Passez nous voir et Ă©coutez une entrevue avec notre nouveau PDG.Qu'est-ce que l'opĂ©rateur -> en C ++?
C'est une vieille question piÚge. En C ++, il n'y a pas d'opérateur ->. Considérer ce qui suit:if (p-->m == 0) f(p);
Bien sĂ»r, cela ressemble Ă une sorte d'opĂ©rateur -> et avec une dĂ©claration appropriĂ©e p et m, vous pouvez mĂȘme compiler et exĂ©cuter ceci:int p = 2;
int m = 0;
if (p-->m == 0) f(p);
Cela signifie en fait: voyez si p-- est supérieur à m (tel qu'il est), puis comparez le résultat (vrai) avec 0. Eh bien, vrai! = 0, donc le résultat est faux et f () n'est pas appelé. En d'autres termes:if ((p--) > m == 0) f(p);
Veuillez ne pas consacrer trop de temps Ă ces questions. Ils Ă©taient populaires pour confondre les dĂ©butants avant mĂȘme l'invention du C ++.Le meilleur guide et liste de livres C ++
Malheureusement, il n'y a pas de liste canonique de livres C ++. Cela, en principe, ne peut pas l'ĂȘtre. Tout le monde n'a pas besoin des mĂȘmes informations, tout le monde n'a pas la mĂȘme expĂ©rience et les meilleures pratiques C ++ Ă©voluent constamment.J'ai fait une petite recherche sur Internet et trouvĂ© un ensemble Ă©tonnant de recommandations. Beaucoup Ă©taient sĂ©rieusement dĂ©passĂ©s et certains Ă©taient tout simplement mauvais. Un dĂ©butant Ă la recherche d'un bon livre sans guide sera trĂšs confus!Vous avez vraiment besoin d'un livre parce que les mĂ©thodes qui rendent C ++ efficace ne sont pas faciles Ă trouver sur plusieurs blogs sur des sujets spĂ©cifiques, et bien sĂ»r les blogs souffrent Ă©galement d'erreurs, d'obsolescence et de mauvaises explications. Souvent, ils se concentrent Ă©galement sur de nouveaux sujets avancĂ©s et ignorent les principes de base.Je recommande monProgrammation: principes et pratiques d'utilisation du C ++ (2e Ă©dition) pour les personnes qui commencent tout juste Ă apprendre Ă programmer, et de la visite C ++ (2e Ă©dition) pour les personnes qui sont dĂ©jĂ programmeurs et qui ont besoin de se familiariser avec le C ++ moderne. Les personnes ayant une solide formation en mathĂ©matiques peuvent commencer par DĂ©couvrir le C ++ moderne: un cours intensif pour les scientifiques, les ingĂ©nieurs et les programmeurs Peter Gottschling.Une fois que vous commencez Ă utiliser C ++ pour de vrai, vous aurez besoin d'un ensemble de directives pour faire la distinction entre ce qui peut ĂȘtre fait et ce qui est une bonne pratique. Pour cela, je recommande les directives de base C ++ sur GitHub.Pour une bonne brĂšve explication des caractĂ©ristiques et fonctions de chaque langue de la bibliothĂšque standard, je recommandewww.cppreference.com .# 4. Quelles sont les diffĂ©rences entre une variable pointeur et une variable de rĂ©fĂ©rence en C ++?
Pour en savoir plus sur les liens et les pointeurs, consultez Learn C ++ .Les deux sont représentés en mémoire comme une adresse machine. La différence réside dans leur utilisation.Pour initialiser le pointeur, vous lui donnez l'adresse de l'objet:int x = 7;
int* p1 = &x;
int* p2 = new int{9};
Pour lire et écrire à travers un pointeur, nous utilisons l'opérateur de déréférence (*):*p1 = 9;
int y = *p2;
Lorsque nous attribuons un pointeur Ă un autre, ils pointeront tous deux vers le mĂȘme objet:p1 = p2;
*p2 = 99;
int z = *p1;
Notez qu'un pointeur peut pointer vers diffĂ©rents objets au cours de son cycle de vie. C'est la principale diffĂ©rence avec les liens. Le lien est attachĂ© Ă l'objet lors de sa crĂ©ation et ne peut pas ĂȘtre converti en lien vers un autre.Pour les rĂ©fĂ©rences, le dĂ©rĂ©fĂ©rencement est implicite. Vous initialisez le lien avec l'objet et le lien obtient son adresse.int x = 7;
int& r1 = x;
int& r2 = *new int{9};
Le nouvel opérateur renvoie un pointeur, j'ai donc dû le déréférencer avant l'affectation, en l'utilisant pour initialiser le lien.Pour lire et écrire via un lien, nous utilisons simplement le nom du lien (sans déréférencement explicite):r1 = 9;
int y = r2;
Lorsque nous attribuons un lien à un autre, la valeur spécifiée sera copiée:r1 = r2;
r1 = 99;
int z = r2;
Les références et les pointeurs sont souvent utilisés comme arguments d'une fonction:void f(int* p)
{
if (p == nullptr) return;
}
void g(int& r)
{
}
int x = 7;
f(&x);
g(x);
Il peut y avoir un pointeur nullptr
, nous devons donc vérifier s'il indique quelque chose. à propos du lien, vous pouvez initialement supposer qu'il fait référence à quelque chose.# 5. Comment parcourir les mots chaßne?
Utilisez stringstream
, mais comment définissez-vous un "mot"? Pensez: "Marie avait un petit agneau." Le dernier mot est «agneau» ou «agneau».? S'il n'y a pas de ponctuation, c'est facile:vector<string> split(const string& s)
{
stringstream ss(s);
vector<string> words;
for (string w; ss>>w; ) words.push_back(w);
return words;
}
auto words = split("here is a simple example");
for (auto& w : words) cout << w << '\n';
ou simplement:for (auto& w : split("here is a simple example")) cout << w << '\n';
Par défaut, l'opérateur >> saute les espaces. Si nous avons besoin d'ensembles de délimiteurs arbitraires, les choses deviennent un peu plus confuses:template<typename Delim>
string get_word(istream& ss, Delim d)
{
string word;
for (char ch; ss.get(ch); )
if (!d(ch)) {
word.push_back(ch);
break;
}
for (char ch; ss.get(ch); )
if (!d(ch))
word.push_back(ch);
else
break;
return word;
}
d est une opération indiquant si le caractÚre est un délimiteur, et je renvoie "" (chaßne vide) pour indiquer qu'il n'y a pas de mot à renvoyer.vector<string> split(const string& s, const string& delim)
{
stringstream ss(s);
auto del = [&](char ch) { for (auto x : delim) if (x == ch) return true; return false; };
vector<string> words;
for (string w; (w = get_word(ss, del))!= ""; ) words.push_back(w);
return words;
}
auto words = split("Now! Here is something different; or is it? ", "!.,;? ");
for (auto& w : words) cout << w << '\n';
Si vous avez une bibliothÚque de plages C ++ 20, vous n'avez pas besoin d'écrire quelque chose comme ça, mais vous pouvez utiliser split_view.Bjarn Straustrup est partenaire technique et directeur général de Morgan Stanley New York et professeur invité à Columbia University. Il est également le créateur de C ++.
Pour plus d'informations sur C ++ 20, voir: isocpp.org .C'est tout. Rendez-vous sur le parcours !