Вы готовы присоединиться к величественному миру программирования C и C++? Хотите ли вы подвергнуть сомнению свое существование после нескольких простых строк C++?
Если ваш ответ "Yeh!", "Yep" или "Why not?" - добро пожаловать на проверку ваших знаний. Вам будет предложено несколько вопросов, связанных с C или C++.
Правильные ответы и пояснения вы найдете в конце истории. Удачи!
main;
Что произойдет, если вы попытаетесь скомпилировать эту программу с помощью компилятора C?
#include <iostream> #include <unistd.h> int main() { for(auto i = 0; i < 1000; i++) std::cout << "Hello world!\n"; fork(); }
Сколько строк напечатает эта программа?
#include <iostream> int main() { int array[] = { 1, 2, 3 }; std::cout << (4, (1, 2)[array]) << std::endl; }
Что напечатает эта программа?
#include <regex> #include <iostream> int main() { std::regex re("(.*|.*)*O"); std::string str("0123456789"); std::cout << std::regex_match(str, re); return 0; }
Сколько времени потребуется, чтобы это регулярное выражение сопоставило данную входную строку?
#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&)
#include <iostream> int x = 0; int bar(int(x)); int main() { std::cout << bar; }
Что напечатает эта программа?
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(); }
Последняя строка, которую выведет эта программа, это…
Foo(int, int)
Foo(const Foo&, int)
Foo(int, const Foo&)
Foo(int)
Надеюсь, вы никогда не найдете ни одного из этих странных фрагментов в дикой природе.
Самая маленькая программа
Это допустимый код C. Он успешно скомпилируется и линкуется. Он зависнет, если вы попытаетесь его запустить. main;
- глобальная переменная.
В коде C можно опустить много вещей. Например, можно опустить тип глобальной переменной. По умолчанию компилятор будет считать, что этот тип — int
. Также в C нет искажения имен (в отличие от C++), поэтому при связывании нет способа отличить переменную 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.
Другие вероятные варианты на удивление долго работают или работают как и ожидалось. Это потому, что есть два возможных подхода к реализации регулярных выражений.
Первое - преобразовать регулярные выражения в конечные автоматы O(n**2)
(n - длина шаблона), сопоставить строку O(m)
(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
скрыт в этой области видимости.