Вы готовы присоединиться к величественному миру программирования C и C++? Хотите ли вы подвергнуть сомнению свое существование после нескольких простых строк C++? Если ваш ответ "Yeh!", "Yep" или "Why not?" - добро пожаловать на проверку ваших знаний. Вам будет предложено несколько вопросов, связанных с C или C++. Правильные ответы и пояснения вы найдете в конце истории. Удачи! 1. Самая маленькая программа main; Что произойдет, если вы попытаетесь скомпилировать эту программу с помощью компилятора C? не будет компилироваться скомпилируется, не будет компоноваться скомпилирует и свяжет 2. Вилка #include <iostream> #include <unistd.h> int main() { for(auto i = 0; i < 1000; i++) std::cout << "Hello world!\n"; fork(); } Сколько строк напечатает эта программа? 1000 менее 1000 более 1000 3. Все, что вам нужно, это индексы. #include <iostream> int main() { int array[] = { 1, 2, 3 }; std::cout << (4, (1, 2)[array]) << std::endl; } Что напечатает эта программа? 1 2 3 4 не будет компилироваться неопределенный 4. Регулярные выражения #include <regex> #include <iostream> int main() { std::regex re("(.*|.*)*O"); std::string str("0123456789"); std::cout << std::regex_match(str, re); return 0; } Сколько времени потребуется, чтобы это регулярное выражение сопоставило данную входную строку? 1 мс 1 сек. 1 мин. 1 час 1 год навсегда 5. Ходы и лямбды #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; } Последняя строка, которую выведет эта программа, это… Foo() Foo(Foo&&) Foo(const Foo&) 6. X и черта #include <iostream> int x = 0; int bar(int(x)); int main() { std::cout << bar; } Что напечатает эта программа? 0 1 0x0 не будет компилироваться не будет ссылки 7. Конструкторы #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(); } Последняя строка, которую выведет эта программа, это… Foo(int, int) Foo(const Foo&, int) Foo(int, const Foo&) Foo(int) Вместо заключения Надеюсь, вы никогда не найдете ни одного из этих странных фрагментов в дикой природе. Ответы Самая маленькая программа Это допустимый код C. Он зависнет, если вы попытаетесь его запустить. - глобальная переменная. Он успешно скомпилируется и линкуется. main; В коде C можно опустить много вещей. Например, можно опустить тип глобальной переменной. По умолчанию компилятор будет считать, что этот тип — . Также в C нет (в отличие от C++), поэтому при связывании нет способа отличить переменную от функции . int искажения имен main main Таким образом, компилятор скомпилирует корректный код, а компоновщик найдет что-то с именем в объектном файле, чтобы скомпоновать программу. main Вилка Это больше функция POSIX, чем функция C или C++. Реализации операций ввода-вывода используют буферы для оптимизации производительности. Когда вы вызываете , ОС создаст копию-при-записи дубликата памяти процесса, буферы ввода-вывода, скорее всего, также будут дублироваться, а буферизованные строки . fork , скорее всего, будут выведены более 1000 раз Все, что вам нужно, это индексы Ответ 3. Чтобы понять этот код, давайте подробнее рассмотрим, как работают индексы в C и C++: — то же самое, что , то же самое, что и то же самое, что . array[index] *(array + index) (index + array) index[array Вторая подсказка — оператор . Это бинарный оператор, он отбрасывает левый аргумент и возвращает правый аргумент. , Регулярные выражения что произойдет! Поведение зависит от реализации. Невозможно предсказать, В моей среде эта программа вызывает исключение The complexity of an attempted match against a regular expression exceeded a pre-set level. Другие вероятные варианты на удивление долго работают или работают как и ожидалось. Это потому, что есть два возможных подхода к реализации регулярных выражений. Первое - преобразовать регулярные выражения в конечные автоматы (n - длина шаблона), сопоставить строку (m - длина строки). Этот подход не поддерживает O(n**2) O(m) возврат. Второй — жадный подход + DFS, поддерживает возврат, но склонен к экспоненциальному росту временной сложности в определенных шаблонах. Движения и лямбды Ответ: . Лямбды по умолчанию неизменяемы, все значения, захваченные в лямбду с помощью неявно являются . Это разблокирует поведение для лямбд. Foo(const Foo&) [] const идемпотентное При перемещении вы создаете . — странный тип, поэтому компилятор просто копирует f const Foo&& const Foo&& Foo Есть два способа исправить это: Создать изменяемую лямбду auto a = [f = std::move(f)]() mutable { return std::move(f); }; Объявить конструктор Foo(const Foo&&) X и полоса . Программа выведет 1 — странный способ объявления функции, он эквивалентен . int bar(int(x)); int bar(int x); Если вы перепутали с приведением типа, - это приведение типа. int bar((int(x))); Затем мы пытаемся неявно привести адрес функции к , результат такого приведения всегда будет . bool true Функция никогда не использовалась, что позволяет нам избежать ошибки неиспользуемого символа при компоновке. bar() Конструкторы Последняя строка — . Foo(const Foo&, int) — это объявление переменной, то же самое, что и . Таким образом, член класса под именем скрыт в этой области видимости. Foo(i) Foo i i