Etes-vous prêt à rejoindre le monde majestueux de la programmation C et C++ ? Voulez-vous remettre en question votre existence après quelques lignes simples de C++ ?
Si votre réponse est « Yeh ! », « Yep » ou « Pourquoi pas ? », n'hésitez pas à tester vos connaissances. Plusieurs questions liées au C ou au C++ vous seront posées.
Veuillez trouver les réponses et les explications correctes à la fin de l'histoire. Bonne chance !
main;
Que se passera-t-il si vous essayez de compiler ce programme à l'aide du compilateur C ?
#include <iostream> #include <unistd.h> int main() { for(auto i = 0; i < 1000; i++) std::cout << "Hello world!\n"; fork(); }
Combien de lignes ce programme imprimera-t-il ?
#include <iostream> int main() { int array[] = { 1, 2, 3 }; std::cout << (4, (1, 2)[array]) << std::endl; }
Qu'est-ce que ce programme va imprimer ?
#include <regex> #include <iostream> int main() { std::regex re("(.*|.*)*O"); std::string str("0123456789"); std::cout << std::regex_match(str, re); return 0; }
Combien de temps faudra-t-il pour que cette expression régulière corresponde à cette chaîne d’entrée ?
#include <iostream> struct Foo { Foo() { std::cout << "Foo()\n"; } Foo(Foo&&) { std::cout << "Foo(Foo&&)\n"; } Foo(const Foo&) { std::cout << "Foo(const Foo&)\n"; } }; int main() { Foo f; auto a = [f = std::move(f)]() { return std::move(f); }; Foo f2(a()); return 0; }
La dernière ligne à imprimer par ce programme est…
Foo()
Foo(Foo&&)
Foo(const Foo&)
#include <iostream> int x = 0; int bar(int(x)); int main() { std::cout << bar; }
Qu'est-ce que ce programme va imprimer ?
0
1
0x0
#include <iostream> struct Foo { Foo() { std::cout << "Foo()\n"; } Foo(const Foo&) { std::cout << "Foo(const Foo&)\n"; } Foo(int) { std::cout << "Foo(int)\n"; } Foo(int, int) { std::cout << "Foo(int, int)\n"; } Foo(const Foo&, int) { std::cout << "Foo(const Foo&, int)\n"; } Foo(int, const Foo&) { std::cout << "Foo(int, const Foo&)\n"; } }; void f(Foo) {} struct Bar { int i, j; Bar() { f(Foo(i, j)); f(Foo(i)); Foo(i, j); Foo(i); Foo(i, j); } }; int main() { Bar(); }
La dernière ligne à imprimer par ce programme est…
Foo(int, int)
Foo(const Foo&, int)
Foo(int, const Foo&)
Foo(int)
J’espère que vous ne trouverez jamais un de ces extraits particuliers dans la nature.
Le plus petit programme
Il s'agit d'un code C légal. Il sera compilé et lié avec succès. Il plantera si vous essayez de l'exécuter. main;
- est une variable globale.
Dans le code C, vous pouvez omettre beaucoup de choses. Par exemple, vous pouvez omettre le type d'une variable globale. Par défaut, le compilateur supposera que ce type est un int
. De plus, il n'y a pas de modification de nom en C (contrairement à C++), donc lors de la liaison, il n'y a aucun moyen de distinguer la variable main
de la fonction main
.
Ainsi, le compilateur compilera un code valide et l'éditeur de liens trouvera quelque chose nommé main
dans le fichier objet pour lier un programme.
La fourchette
Il s'agit davantage d'une fonctionnalité POSIX que d'une fonctionnalité C ou C++. Les implémentations d'opérations d'E/S utilisent des tampons pour optimiser les performances. Lorsque vous appelez fork
, le système d'exploitation crée une copie en écriture de la mémoire du processus, les tampons d'E/S sont susceptibles d'être également dupliqués et les chaînes mises en mémoire tampon sont susceptibles d'être imprimées plus de 1 000 fois .
Tout ce dont vous avez besoin, ce sont des indices
La réponse est 3
Pour comprendre ce code, examinons de plus près le fonctionnement des indices en C et C++ : array[index]
, est identique à *(array + index)
, est identique à (index + array)
et identique à index[array
.
Le deuxième indice est l'opérateur ,
. Son opérateur binaire, il rejette l'argument de gauche et renvoie l'argument de droite.
Expressions régulières
Il est impossible de prédire ce qui va se passer ! Le comportement dépend de la mise en œuvre.
Dans mon environnement, ce programme génère l'exception The complexity of an attempted match against a regular expression exceeded a pre-set level.
D'autres options possibles sont un temps étonnamment long ou un fonctionnement conforme aux attentes. C'est parce qu'il existe deux approches possibles pour implémenter les expressions régulières.
Premièrement, transformez les expressions régulières en automates finis O(n**2)
(n - longueur du motif), faites correspondre la chaîne O(m)
(m - longueur de la chaîne). Cette approche ne prend pas en charge le retour en arrière.
Deuxièmement, l'approche gourmande + DFS, prend en charge le retour en arrière mais est sujette à une complexité temporelle exponentielle sur certains modèles.
Mouvements et lambdas
La réponse est Foo(const Foo&)
. Les lambdas sont immuables par défaut, toutes les valeurs capturées dans lambda avec []
sont implicitement const
. Cela débloque le comportement idempotent pour les lambdas.
Lorsque vous déplacez f
vous créez const Foo&&
. const Foo&&
est un type étrange, donc le compilateur copie simplement Foo
Il existe deux manières de résoudre ce problème :
Créer un lambda mutable
auto a = [f = std::move(f)]() mutable { return std::move(f); };
Déclarer le constructeur Foo(const Foo&&)
X et barre
Le programme imprimera 1
.
int bar(int(x));
— est une manière étrange de déclarer une fonction, elle est égale à int bar(int x);
.
Si vous confondez avec le type cast, int bar((int(x)));
- c'est un type cast.
Ensuite, nous essayons de convertir implicitement l'adresse de la fonction en bool
, le résultat d'une telle conversion est toujours true
.
La fonction bar()
n'a jamais été utilisée, ce qui nous permet d'éviter l'erreur de symbole non référencé lors de la liaison.
Constructeurs
La dernière ligne est Foo(const Foo&, int)
.
Foo(i)
est une déclaration de variable, identique à Foo i
. Ainsi, le membre de classe sous le nom de i
est masqué dans cette portée.