Advertisement
Yakov

FIVT2020.C++.Answers

Dec 23rd, 2020
870
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 9.86 KB | None | 0 0
  1. Задача 1.
  2. CE возникает из-за того, что выражение (x > 0 ? ++x : x++) является rvalue, а ему нельзя присваивать.
  3. Даже если изначально проинициализировать x=1, CE не исчезнет. Хоть ++x сам по себе является lvalue, компилятор обязан принять решение относительно всего выражения  (x > 0 ? ++x : x++), чем оно является. Поскольку одна из частей является rvalue, то и все выражение целиком является rvalue, значение x роли не играет.
  4.  
  5. Задача 2.
  6. Возможны 6 вариантов: цифры 123 могут образовывать любую перестановку, на конце обязательно будет 7.
  7. Хоть приоритет оператора * и выше, чем +, нет гарантий относительно того, в каком порядке будут вычисляться значения самих аргументов. У каждого из операторов может сначала вычислиться левый операнд, потом правый, а может наоборот. Отсюда unspecified behaviour.
  8. NB: за ответ “возможны всего 4 варианта” баллы не снижаем. Это детали стандарта, в которые мы не лезем. Главное - наличие пояснения, что порядок 123 не определен, но 7 обязательно будет в конце.
  9.  
  10. Задача 3.
  11. Выведется 2323. Функции inc_value и assign_value_from_ref никак не меняют переданные параметры, так что можно считать, что этих функций нет.
  12. inc_ref(a) увеличивает а (то есть х) на 1.
  13. inc_ref(b) увеличивает b (то есть y) на 1.
  14. assign_ref_from_value(b, y) ничего не меняет, поскольку b и так равно y.
  15. В итоге получаем вывод 23, после чего еще раз то же самое 23.
  16.  
  17. Задача 4.
  18. Тут проблема в том, что поле int& y ничем не проинициализировано перед входом в конструктор. Надо написать список инициализации вместо присваивания полей: A(int xx, int yy): x(xx), y(yy) {}. Конструктор копирования менять не нужно, он сам нормально сгенерится. Правда, теперь есть новая проблема - UB из-за того, что поле y будет висячей ссылкой, ну да вопрос уж не об этом.
  19.  
  20. Задача 5
  21. Ну тут все очевидно, нужен нетривиальный копи-конструктор и оператор присваивания. Проверить, что правильно объяснили проблему и правильно их реализовали.
  22.  
  23.  
  24. Задача 6
  25. Тут надо написать перед мэйном класс-компаратор, определить в нем оператор () как надо, а в самом сете указать его шаблонным параметром.
  26.  
  27. Задача 7
  28. Будет acbABCA.
  29. Сначала создается объект B. При этом сначала создается родитель (а), потом поле наследника (с), потом сам наследник (b).
  30. Потом происходит срезка и копируется родительская часть. Ничего при этом не выводится.
  31. Потом уничтожается объект А (который был копией исходного).
  32. Потом уничтожается исходный объект: сначала деструктор наследника (В), потом поля наследника (С) и в конце родитель (А).
  33.  
  34. Задача 8.
  35. В строке 1 ошибки не будет: Mom может обратиться к полю своего непосредственного родителя, т.к. оно protected.
  36. В строке 2 тоже ошибки не будет. Son может обратиться к полю m своего непосредственного родителя, хоть оно и private, но там написано friend class Son. К полю g он может обратиться, поскольку хоть Granny и приватный родитель, но мама к ней пускает (сын - друг для мамы), а у бабушки поле уже protected, а не private.
  37. В строке 3 будет СЕ во всех трех случаях. s.s защищенное поле, s.m приватное поле, а s.g недоступно, потому что хоть у бабушки и написано friend int main, мама к ней не пускает (наследование приватное).
  38.  
  39. Задача 9
  40. s.g вызывает неоднозначность из-за ромбовидного наследования (важный момент: приватность тут не играет роли, ошибка именно по причине неоднозначности, т.к. доступы проверяются после выбора версии).
  41. static_cast<Mom&> вызывает ошибку доступа, т.к. наследование приватное.
  42. static_cast<Dad&> ошибку не вызывает, но обращение к полям все равно вызывает CE, т.к. поля приватные.
  43. Если заменить на reinterpret, то пропадет ошибка из-за запрещенного каста. Однако обращение к полям все равно нигде работать не будет, т.к. они по-прежнему все приватные.
  44.  
  45. Задача 10
  46. В первом случае выведется 21. 2 - очевидно, а 1 - потому что f в классе Derived реально не оверрайдит f из класса Base (сигнатура не совпадает). Поэтому выбирается версия для Base.
  47. Если раскомментить override, то будет CE - как раз потому, что f обещала оверрайдить, а на самом деле не оверрайдит.
  48.  
  49. Задача 11
  50. Поскольку деструктор родителя вызывается после деструктора наследника, а деструктор родителя не определен, возникает ошибка линковщика. Надо дописать определение деструктора. Сделать это надо вне тела класса: Base::~Base() {}
  51. Если удалить виртуальный деструктор, то для переменной b не будет вызван деструктор Derived, а будет вызван лишь неявно сгенерированный пустой деструктор Base. Как следствие - delete dp не будет сделано, это потенциальная утечка памяти.
  52.  
  53. Задача 12
  54. Компилятор сначала выбирает подходящую версию перегрузки, а затем выбирает подходящую специализацию этой версии, если таковая имеется. В первом случае f(T, T) выигрывает у f(T, U) и поэтому выбирается f(T, T), а специализаций у нее нет. Во втором случае f(int, int) становится специализацией f(T, T), а не f(T, U), поэтому выбирается эта специализация, а не оригинальная версия f(T, T).
  55.  
  56. Задача 13
  57. Параметром шаблона не может быть неконстантная переменная, т.к. компилятор должен в момент компиляции во все шаблоны подставить фиксированные значения переменных, а он не может так поступить с неконстантной переменной. Все заработает, если просто объявить n как const size_t.
  58.  
  59. Задача 14
  60. По стандарту компилятор парсит строку S<T>::x * a; как выражение, а не как объявление. Он не может парсить ее по-разному в зависимости от T, так как он должен еще до шаблонной подстановки уметь проверять корректность синтаксиса, в частности, отличать объявления от выражений. Поэтому возникает ошибка “а - необъявленная переменная”. Можно исправить ошибку двумя способами: 1) дописать typename перед этой строкой, и тогда он будет парсить это как объявление; 2) объявить переменную a где-то перед этой строкой, тогда он успешно распарсит это как выражение.
  61.  
  62. Задача 15
  63. Например, так:
  64. template<typename T>
  65. struct remove_all_extents {
  66.     using type = T;
  67. };
  68.  
  69. template<typename T>
  70. struct remove_all_extents<T[]> {
  71.     using type = remove_all_extents<T>;
  72. };
  73.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement