LINUX.ORG.RU

Какой должен быть тест на базовые знания C++?

 ,


0

3

Недавно видел тест, «Базовый C++», который предлагают нашим инженерам-программистам. Видимо, хотят понять, вдупляем ли мы вообще C++ или требуется обучение.

Но тест не про это, что вообще характерно для плюсов. Вернее, только первую треть вопросов можно отнести к категории «базовый C++», потому что там действительно вопросы на базовое понимание синтаксиса и семантики фич.

Вторая часть была полна каких-то наркоманских примеров, какие-то многострочные выкрутасы с вовлечением RTTI, дичайшей арифметикой на указателях, кастами, словом, такого кода, который может даже не скомпилироваться (были грамматически некорректные примеры). Я даже не говорю о том, что на столько это все забористо выглядело, что не прошло бы ни одно вменяемое ревью, если бы кто-то захотел включить такое в продакшн.

Некоторые вопросы были явно составлены «на отвали», с явными грамматическими опечатками в коде. Ответы на некоторые вопросы зависили от компилятора. Например, если компилятор оптимизирует хвостовую рекурсию, никакой стек не переполнится, а программа будет бегать в цикле вечно, но ответа «выполняться вечно», конечно же, не было.

Последняя часть меня просто убила. Там были задания, как будто вот с этих ваших писькомерных сайтов с задачками на C++ или олимпиады, вообще никакого отношения к теме «базовый C++».

И вот я подумал, от чего так? Почему люди концентрируют внимание на какой-то укуренной белиберде - которую у джунов надо наоборот вытравливать на ранних стадиях, чтобы писали надежный, читаемый и поддерживаемый код - а не на том, что кодеру нужно будет в реальной работе? Ведь дофига есть актуальных тем, например, современные фичи C++, как писать безопасный код, параллельные вычисления, стандартная библиотека. Складывается такое ощущение, что такие тесты пишут какие-то сычи, которые специализируются на олимпиадах и говнокоде, на каких-то нахрен никому не нужных редких правилах C++.

★★★★★
Ответ на: комментарий от bugfixer

(а) исключения относительно недавнее нововведение

относительно чего? Времен юности мейнфреймов - да, пожалуй. Хотя впрочем уже в PL/I была какая-то форма исключений.

seiken ★★★★★
() автор топика
Последнее исправление: seiken (всего исправлений: 1)
Ответ на: комментарий от seiken

(а) исключения относительно недавнее нововведение

относительно чего? Времен юности мейнфреймов - да, пожалуй. Хотя впрочем уже в PL/I была какая-то форма исключений.

Перефразирую - они стали zero cost on non-exceptional code paths относительно недавно. До этого народ частенько сознательно воздерживался от их использования.

bugfixer ★★★★★
()
Ответ на: комментарий от rumgot

Этим я доказал, что когда возникает необходимость использовать C++ по прямому его назначению, а именно для оптимизации горячих кусков программы, то синтаксический сахар мешает. То же самое в специфических средах вроде ядра или MCU. Или в базовой библиотеке, которую не жалко оверинженерить.

Если необходимости оптимизировать нет, то оптимальнее решать задачу на чем-нибудь вроде Go или Python. Всё это, конечно, не отменяет упоротых продакшенов, в которых на C++ используют просто потому, что так решили 10-20 лет назад.

snizovtsev ★★★★★
()
Последнее исправление: snizovtsev (всего исправлений: 1)
Ответ на: комментарий от snizovtsev

Ну синтаксический сахар бывает разный. Если это сахар STL для решения общих задач, то мешает. Если это узкозаточенный сахар то нет. Никто же не мешает сделать контейнер эффективно реализующий вектор векторов например и обмазать его сахаром - будет ничуть не хуже ручного низкоуровнего решения, но смотреться будет куда симпатичнее.

Если необходимости оптимизировать нет, то оптимальнее решать задачу на чем-нибудь вроде Go или Python.

Про Go ничего не знаю, а у питона есть своя ниша. Если задача из этой ниши - да, будет хорошо. Если нет, то будет плохо. Да и просадка по производительности на 2-3 порядка не всегда прокатывает.

AntonI ★★★★★
()
Ответ на: комментарий от snizovtsev

Да брось ты. В продакшен не часто нужно реализовывать структуры данных.

Если необходимости оптимизировать нет, то оптимальнее решать задачу на чем-нибудь вроде Go или Python

Ага. Чтобы потом думать, что оптимизировать.

rumgot ★★★★★
()
Ответ на: комментарий от rumgot

В продакшен не часто нужно реализовывать структуры данных.

Смотря что подразумевать под «реализовывать структуры данных». Как полновесные generic containers - да, не часто. А как какое-нибудь хитросплетение существующих контейнеров для конкретного случая - не каждый день конечно, но регулярно (ну пусть будет - раз в месяц).

bugfixer ★★★★★
()

Это все задротские понты чтоб интервьюэр мог поумничать, обычно не стоящие ни хрена с точки зрения реальной применимости: если кодовая база состоит из «приветов из 90-х» где ехал UB через UB, понты про новые стандарты выглядят смешно, т.к. не будет ничего переписано примерно никогда («кто за это заплатит?»), а если код не должен быть эзотерическим, а вовсе даже сопровождабельным, понятным и стандартным — запоминание костылей, которыми подпирают убожество «решений» тем более не достойно разумных людей, т.к. эти костыли станут (или стали) депрекейтед и «код воняет» в следующей итерации «бестпрактисов».

slackwarrior ★★★★★
()
Последнее исправление: slackwarrior (всего исправлений: 2)
Ответ на: комментарий от snizovtsev

«Оптимальность» нужно пруфать. И чаще всего не пяткой в груть. И не наколенными профайлерами, написанными «в олимпиадном стиле»... а таки формально пруфать — доказухой той индуктивной гипотезы, которой является «оптимизированный» код. Т.е. критерий оптимальности + формально корректное доказательство. Иначе это все велосипедостроение ради него самого.

slackwarrior ★★★★★
()
Ответ на: комментарий от slackwarrior

Т.е. критерий оптимальности + формально корректное доказательство. Иначе это все велосипедостроение ради него самого

Блин, где ж Вы раньше были, я Вас заждался :)

bugfixer ★★★★★
()
Ответ на: комментарий от eao197

мне пофиг что мне за такие высказывания будет

Мне кажется - Вы зря переживаете. Если что - апеллируйте сюдымс, а там потом посмотрим чем всё закончится.

Ну, и чтобы до конца понять с кем мы имеем дело - рекомендую одним глазком глянуть ;)

bugfixer ★★★★★
()
Ответ на: комментарий от bugfixer

Ну, и чтобы до конца понять с кем мы имеем дело - рекомендую одним глазком глянуть ;)

Ага, 20 лет в real-time и gamedev. Отношение к исключениям понятно, там же их либо нет как класса, либо они допустимы лишь на этапе инициализации.

А вот категоричность суждений удивляет еще сильнее. За 20 лет-то можно насмотреться настолько много всякого разного, чтобы убедится, что «единственно правильных» путей (мнений, решений) не бывает.

eao197 ★★★★★
()
Ответ на: комментарий от bugfixer

До этого народ частенько сознательно воздерживался от их использования.

Еще одной причиной от них отказываться в 90-х было то, что в разных компиляторах поддержка исключений была на разном уровне.

Мне вот запомнилось, как пришлось портировать библиотеку на Linux после Win32 и OS/2, а на Linux-е был какой-то gcc (вроде 2.95), который не мог ловить исключения по ссылке на базовый класс. Т.е. если у нас есть:

class exception_base {...};
class invalid_data : public exception_base {...};
...
try {
  ...
  throw invalid_data(...);
}
catch(const exception_base & x) {
  ... // (1)
}

то в точку (1) с той версией gcc мы бы не попали.

По моим ощущениям, нормально использовать исключения везде (безотносительно их производительности), стало где-то в районе 2000-го года. До этого были высоки шансы где-то на какие-то грабли наступить.

eao197 ★★★★★
()
Ответ на: комментарий от bugfixer

А, чуть не забыл - очереди «ивентов» - наше всё.

Да я и сам уже больше 20 лет занимаюсь инструментом, в котором очереди сообщений – это вообще все (ну почти) :)

eao197 ★★★★★
()
Ответ на: комментарий от bugfixer

А, чуть не забыл - очереди «ивентов» - наше всё.

багсеттер, не надо меня напевать, как рабинович карузо. сначала выучите нотную грамоту, что-ли. вы и перевираете и фальшивите, и голоса нет

мало того, что я бы никогда не сказал - «очередь ивентов», а сказал бы «очередь сообщений», так еще бы про мьютекс сказал бы что это ОДИН из фундаментальных примитивов.

alysnix ★★★
()
Последнее исправление: alysnix (всего исправлений: 1)
Ответ на: комментарий от bugfixer

вы даже не понимаете фундаментальной разницы между ивентом, и сообщением. а тот, кто ее понимает, никогда их не «перепутает». то есть либо вы не понимаете разницы и морозите что в голову придет, выдавая это за мои слова, либо намеренно лжете.

очередь «ивентов» может иметь место, но это частный технологический случай очередей вообще. очередь же сообщений - это «канал» в терминологии асинхронных процессов. учи нотную грамоту, рабинович

alysnix ★★★
()
Последнее исправление: alysnix (всего исправлений: 1)
Ответ на: комментарий от bugfixer

госпидя, какой дурак. азербайджанцы с рынка тоже поршики обсуждают, какое отношение имеют поршики к очередям и асинхронным процессам?

вы хоть понимаете степень неадекватности своих «аргументов»?

alysnix ★★★
()
Ответ на: комментарий от eao197

Гугл не использует исключений потому, что изначально он их не использовал, а потом внедрение исключений в уже накопленную кодовую базу оказалось слишком дорогим.

Я бы сказал, по другой причине. В Гугле распостранена порочная практика все вопросы решать коммитетами. И вот у них коммитет по С++ из нескольких человек решил за всю многотысячную компанию, как им писать код на С++. Но по этому стайлгайду можно судить, что люди в их коммитете толком не шарили в современном С++, так как там явно видны устарелые предрассудки и практики даже на время написания гайда.

rupert ★★★★★
()
Ответ на: комментарий от rupert

Мне неизвестно что там и как в Google, поэтому опираюсь лишь на то, что написано.

Однако, использовать исключения в C++ в середине-конце 1990-х было достаточно рискованным мероприятием. Многие от исключений держались в стороне и если кодовая база начиналась без исключений, то добавить в нее исключения может быть очень рискованной затеей.

eao197 ★★★★★
()
Ответ на: комментарий от rupert

В Гугле распостранена порочная практика все вопросы решать коммитетами.

а в чем порочность решений «экспертного совета»? альтернативы тут или самоличный волюнтаризм начальства, или махновщина - типа я художник, я так вижу.

alysnix ★★★
()
Ответ на: комментарий от eao197

то добавить в нее исключения может быть очень рискованной затеей.

никакого риска. пример с std::filesystem уже приводился. заворачивайте свой код без эксепшенов в экспешены и имейте два варианта, если ексепшены вам так нужны.

в чем риск?

alysnix ★★★
()
Ответ на: комментарий от alysnix

Сударь, вас учить только портить.

Вы смотрите на std::filesystem и вам кажется, что исключения там только по требованию пользователя. Но вы, мягко говоря, в упор ничего не видите.

Например, есть класс std::filesystem::path с набором конструкторов. Только два из них помечены как noexcept.

А теперь внимание, вопрос, как вы заставите не-noexcept конструкторы не бросать исключения?

И вопрос со звездочкой: как теперь смотреть на функции из std::filesystem, которые принимают std::filesystem::path?

Вопросы, в вашем случае, риторические.

eao197 ★★★★★
()
Ответ на: комментарий от eao197

если кодовая база начиналась без исключений, то добавить в нее исключения может быть очень рискованной затеей

Никто и не говорит про добавление исключений с бухты-барахты. Есть отработанные методики преобразования кодовой базы к exception-safe виду. Это делатся практически механическим образом. Профит в этом есть достаточно большой, так как даже без использования исключений, exception-safe код является более надёжным. А новый код нужно было сразу писать в exception-safe стиле. Уже за 10 лет могли бы всё это сделать, если бы сразу правильно задали направление развития своей кодовой базы.

rupert ★★★★★
()
Ответ на: комментарий от rupert

Тут я ничего прокомментировать не могу, в управлении такой ордой программистов, работающих над такого объема базой, не копенгаген. Могу только порадоваться, что не мне нести за подобное ответственность :)

eao197 ★★★★★
()
Ответ на: комментарий от eao197

А теперь внимание, вопрос, как вы заставите не-noexcept конструкторы не бросать исключения?

а их не надо ничему заставлять. если они бросят исключения, а вы их не перехватите, ваш код вывалится по неперехваченному исключению. что говорит о том, что он некорректен. поскольку поломать конструктор пути можно только некорректными параметрами.

а если вы их будете перехватывать, то все, что можно тут сделать - вывести то-то в лог и упасть… что мало отличается от неперехвата.

а если вас так парит неперехваченное исключение, пользуйтесь nothrow конструктором.

зы. а если хочется совсем красиво работать с std::filesystem, то надо на самом верху написать перехватчик std::file_system_error(или как оно там), а потом повсеместно пользоваться nothrow функциями.

alysnix ★★★
()
Последнее исправление: alysnix (всего исправлений: 1)

все что вас должно волновать - способен ли человек читать и понимать написанное, тчк.

поэтому единственный вменяемый тест, который действительно многое расскажет о кандидате - 5 минут на чтение и 5 минут на пересказ.

после пересказа можете задать дополнительные вопросы - текст ничем не смущает? вопросов не появилось? как бы мог выглядеть идеальный текст? а с другими персонажами? а в другой обстановке? а в сильно другой обстановке? а если бы автором был (имя любого известного вам певца ртом)? а если автор он же, но под веществами?

а если пересказ курочки рябы вас не впечатлил то задавать кандидату какие либо дополнительные вопросы не имеет смысла.

olelookoe ★★★
()
Ответ на: комментарий от eao197

прикоснитесь вот к этому.

https://en.cppreference.com/w/cpp/filesystem/copy_file

пример там просто прекрасен. он открыт и надежен. есть критика по примеру?

alysnix ★★★
()
Последнее исправление: alysnix (всего исправлений: 1)
Ответ на: комментарий от alysnix

пример там просто прекрасен

Вы его находите прекрасным? Ну афигеть.

Там же непойманных исключений чуть меньше, чем овердофига.

Это же, исходя из ваших убеждений, должно быть ай-ай-ай.

eao197 ★★★★★
()
Ответ на: комментарий от eao197

Вы его находите прекрасным? Ну афигеть.

сарказм детектор вам кто-то сломал.

Там же непойманных исключений чуть меньше, чем овердофига.

ну наконец-то. ну вот и запишите чтобы все было «надежно», и чтобы глаза не сломать. и кладите сюда. вы же любите исключения.

alysnix ★★★
()
Последнее исправление: alysnix (всего исправлений: 1)
Ответ на: комментарий от alysnix

ну вот и запишите чтобы все было «надежно», и чтобы глаза не сломать. и кладите сюда.

Мне это зачем?

Вы нишмагли ни с safe_int32, и со списками инициализации. Схерали вам что-то кто-то должен?

вы же любите исключения.

Скажем так, у меня есть надежда, что более-менее научился ими пользоваться.

Однако же, возвращаемся к исходному вопросу (очередному):

Скажите, пожалуйста, а где-то в открытом доступе ваш код есть?

eao197 ★★★★★
()
Ответ на: комментарий от eao197

ну вот. я вам дал тупой код любителей эксепшенов, где навскидку в 14 строках неперехвачено 7 штук возможных эксепшенов, зато перехвачен один.

если все написать правильно, то код вырастет не менее чем вдвое, а то и втрое.

потому вам стыдно все это написать, и положить. понятно чем дело кончится.

какие-то ваши мифические int32 никаким кодом не сопровождались, а сопроводжались нытьем, что ваша косорукая псевдо реализация хочет экспешена в операторе +. на что вам ответили, что арифметический оператор суммы не должен бросать исключений. вопрос закрыт.

alysnix ★★★
()
Ответ на: комментарий от alysnix

если все написать правильно

Чтобы написать правильно нужно знать условия задачи. Они в этом примере не указаны. Можно предполагать, что целью было показать как можно перехватывать исключение из бросающего copy_file. Если так, то цель достигнута.

то код вырастет не менее чем вдвое, а то и втрое.

Говорят, что сдуру и МПХ ломают.

какие-то ваши мифические int32 никаким кодом не сопровождались

А там нужен был код? Ваш уровень интеллекта продолжает поражать.

Ну, ОК. Пусть будет что-то вроде:

namespace impl {
  class safe_int32_builder_t; // Определен в другом месте.
}

class safe_int32 {
  friend class impl::safe_int32_builder_t;

  int32_t value_{};

  // Этот инициализирующий конструктор может дернуть
  // только safe_int32_builder_t;
  safe_int32(int32_t v) // Смело предполагаем, что v корректен.
    : value_{v}
  {}
public:
  safe_int32() = default;

  [[nodiscard]] int32_t value() const { return value_; }
};

Для простоты noexcept нигде не расставлял.

Нужно написать safe_int32 operator+(safe_int32, safe_int32) который не допускает переполнения для int32. Если такое переполнение диагностируется, то следует об этой ошибке проинформировать в run-time.

на что вам ответили, что арифметический оператор суммы не должен бросать исключений

И что, мне нужно поблагодарить, что на три буквы не послали?

Ответили так либо потому, что нишмагли вообще ничего, либо потому что тупой как пробка.

вопрос закрыт.

Не-а.

Ну и да, Карфаген должен быть разрушен:

Скажите, пожалуйста, а где-то в открытом доступе ваш код есть?

eao197 ★★★★★
()
Ответ на: комментарий от slackwarrior

Не нужно строить суперлабу, чтобы измерить потребление памяти и cache misses на задаче «вход-выход». Достаточно time -v и perf.

Кроме того, там нужно было хранить дерево. А в дереве adjacency lists будет иметь известное число элементов 2*(|V|-1), т.е. большинство внутренних векторов будут очень короткими.

Если вы придрались к слову «максимально», то, как мне казалось очевидно, это гипербола (в литературном смысле). Кроме суперизученных задач вроде сортировок вообще мало где есть пруф нижней оценки сложности, и к практической архитектуре процессора вся эта теория слабо применима. Уверен, вы и сами ни разу «формально не пруфали индуктивные гипотезы «оптмизированного» кода». Для индустрии нормально просто сравнивать 2 кода А и Б железе X и Y, подсчитывая попугаи.

snizovtsev ★★★★★
()
Последнее исправление: snizovtsev (всего исправлений: 1)
Ответ на: комментарий от alysnix

я вам дал тупой код любителей эксепшенов https://en.cppreference.com/w/cpp/filesystem/copy_file

Блиннннннн. Дядя, это демонстрационный код. Там люди не ставили задачу поймать все возможные и невозможные типы исключений. Если для тебя это не очевидно, то разберись с собой в первую очередь.

rumgot ★★★★★
()
Ответ на: комментарий от eao197

то следует об этой ошибке проинформировать в run-time.

у вас есть масса способов «проинформировать в рантайме» и без исключений языка. когда вы делите на ноль - вас об этом проинформируют.

как вы будете пользоваться данной информацией вот в чем вопрос. вы будете заворачивать в try-catch все выражения со своими int32? или вы забьете болт на эксепшены, как в приведенном мной примере с копированием файла, поскольку написать все это правильно - слишком мусорно и малочитабельно?

alysnix ★★★
()
Ответ на: комментарий от alysnix

у вас есть масса способов «проинформировать в рантайме» и без исключений языка

Хватить юлить, код покажите?

как вы будете пользоваться данной информацией вот в чем вопрос.

Таки почему вас это так интересует?

Внимательный вы мой, напоминаю, что если вам задают вопросы, то это потому, что от вас хотят получить ответы.

Если вместо ответов вы задаете свои вопросы, игнорируя интересы собеседника, то это, мягко говоря, не способствует конструктиву.

eao197 ★★★★★
()
Ответ на: комментарий от alysnix

написать все это правильно - слишком мусорно и малочитабельно

Ага, а когда я привел пример, где нужно последовательно вызывать несколько функций и каждую следующую вызывать только при условии успеха предыдущей и там видно, что в случае исключений код проще, то ты это проигнорировал, наверное потому, что это не укладывается в твою стройную теорию.

rumgot ★★★★★
()
Ответ на: комментарий от rumgot

Если для тебя это не очевидно, то разберись с собой в первую очередь.

понятно, что демонстрационный, но даже дему можно было завернуть в общий try-catch, чтобы оно стало элементарно приличным. а заворачивать только одну функцию и только в одном месте - это треш.

а если не завернул в общий try-catch, то используй функции что не кидают исключений, они в либе есть.

alysnix ★★★
()
Ответ на: комментарий от rumgot

Вот не нужно этого, НО … Можно было бы миллион чего сделать.

все должно быть логичным и интуитивно понятным. непонятно правильное оформление вызова функции, кидающей исключения, при том что вокруг еще семь штук вызовов, где на исключения забит болт. что хотели сказать авторы таким кодом? они хотели нас научить как обрабатывать исключения в таком случае? они нас этому не научили, а только все испортили.

alysnix ★★★
()
Ответ на: комментарий от rumgot

Ага, а когда я привел пример, где нужно последовательно вызывать несколько функций и каждую следующую вызывать только при условии успеха предыдущей и там видно, что в случае исключений код проще, то ты это проигнорировал, наверное потому, что это не укладывается в твою стройную теорию.

тогда так. короче просто невозможно.

if (not f1(..) or not f2(..) or not f3(..) ..or not fN(..))
 return false;
alysnix ★★★
()
Ответ на: комментарий от rumgot

вот чем лучше функция f(…, Error &ferr);

прямо в месте вызова видно, что она может завершиться с ошибкой. если последующий код эту ошибку никак не обрабатывает - значит тут проблема.

но если функция просто бросает исключения, то если нет прямого перехвата исключения от нее, в месте вызова вообще непонятно - способна ли она сломаться или нет.

вопрос - какой код проще проверять на корректность?

alysnix ★★★
()
Ответ на: комментарий от alysnix

Ты шлангуешь специально? Там не было цели все перехватить. Там покаазли пример использования. Если ты этого не понимаешь… Или ты понимаешь, но хочешь разводить демагогию.

rumgot ★★★★★
()