LINUX.ORG.RU

Что отличает юниора от более продвинутого

 , скиллы


3

7

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

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

★★★★★

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

Несложно угадать, что речь про фабричный метод.

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

Зато все остальные методы другие. И реализация этих классов другая.

QString остался, но реализован в Qt4 совершенно по-другому и api у него сильно поменялся. Модули Network, GL, Sql написаны с нуля. QStringList реализован по-другому. У лайоутов совершенно другой api. Таблицы вообще по-другому устроены.

И тд. Это только то, что я просмотрел.

20-30% может и осталось старого, но для такого проекта - это фактически «с нуля».

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

У джуна как правило ЧСВ и он не может самостоятельно эффективно решать задачу. «мидл» может, но кто ж ему даст, кроме как сапогом по морде. А сеньёр даже если не может, ему приходится выкручиваться, ужом извиваться, но делать всё самостоятельно. Да ещё объяснять почему он это сделал именно так... И ещё пару джунов пнуть и им таски раздать, и разжевать...

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

Помнится, у Страуструпа в C++ Programming Language была целая глава про подходы к обработке ошибок с разбором их достоинств и недостатков.

Не Страуструп, но про разные варианты обработки ошибок. https://www.youtube.com/watch?v=Fno6suiXLPs

anonymous
()
Ответ на: комментарий от RazrFalcon

что именно вы делаете в своих обработчиках исключений?

А какая разница?

IMHO, ты не правильно используешь исключения. Суть в том, что они не должны использоваться для реализации логики. Т.е. вылетело исключение одного типа - делаем одно, другого - другое, такого быть не должно. Исключение - это значит произошла исключительная ситуация (крайне редкая или непредсказуемая), эту ветку выполнять нельзя (максимум можно различить, есть ли у исключения метод what(), чтобы вывести текст в лог или такого метода нет). Для того, что ты делаешь, нужно использовать коды возврата, optional, пару [value,ok_status], как в GoLang (по сути тот же optional), другие варианты, которые ВОЗВРАЩАЕТ вызываемая функция.

Исключение означает «все, трындец, тут ловить нечего, очищаем ресурсы через RAII и выходим на твердую землю». Приложение не должно кидать исключения, если не произошло что-то типа недостатка памяти или отсутствия необходимого файла конфигурации, и в этих случаях почти неважно, выдаст программа сообщение сама, или плюсовый runtime отобразит содержимое exception.what(), при любом раскладе работать дальше приложение не сможет.

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

Спорно.

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

Если я парсю число из строки, а там не число, то будет исключение (у того же stoi), но мне, зачастую, не нужно «падать» в этом случае, а нужно как-то обработать это. Отсюда и растет лапша из try-catch.

PS: я как раз optional + result и использую вместо исключений.

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

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

Примеры смотри в коде Жениного проекта :) А читать про это в любой статье про exception safaty. Обязательно нужно обеспечить хотя бы базовый уровень безопасности (Wiki)

Basic exception safety, also known as a no-leak guarantee: Partial execution of failed operations can cause side effects, but all invariants are preserved and there are no resource leaks (including memory leaks). Any stored data will contain valid values, even if they differ from what they were before the exception.

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

anonymous
()
Ответ на: комментарий от RazrFalcon

А на деле - просто напоминание для программиста без каких-либо гарантий.

По этому вопросу мы с Женей уже мерялись конечностями. Суть такова: если у тебя для noexcept метода есть исходики (его самого и методов, которые он вызывает), то в простейших случаях тебя предупредит gcc (но не clang), а в остальных coverity. Если исходников нет, то никто не знает, кидает ли метод исключения.

Однако, в современном мире уже никто или почти никто не пользуется в C++ библиотеками без исходников, а если и пользуется, то они чисто сишные и исключений не бросают. Так что noexcept можно доверять близко к 100%.

anonymous
()
Ответ на: комментарий от RazrFalcon

Соответственно узнать наличие исключения в них не получится.

Вообще-то, получится. http://en.cppreference.com/w/cpp/error/current_exception

Но, тут суть не в этом. Суть в том, что при использовании RAII деструктор вызовется всегда и очистит ресурсы. Тут логика не такая, как ты привык, типа вылетело одно исключение - делаем один откат, вылетело другое - другой. Тут логика такая, что для каждого объекта, у которого нет своего деструктора (например для указателя) создается объект-защитник, который вызовет деструктор объекта. Т.е. вместо голого указателя создаем std::unique_ptr, который в своем деструкторе вызовет деструктор защищаемого объекта. И произойдет это при любом случае - было исключение или нет.

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

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

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

Garbage Collector, финализаторы и IDisposable+using(try with resources).

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

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

Был бы очень рад следующим изменениям:

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

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

- если для создания нового узла в данном (связном) списке не хватает памяти, то происходит аварийное завершение программы (вариант: вызов специального обработчика, которому передаётся исключение из деструктора).

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

IDisposable вполне может валиться, и так далее, кроме того есть паттерн DisposableObject, который разграничивает какие ресурсы освобождать в финализаторе а какие в Dispose

Ну и GC от 90% проблем, для которых надо RAII, защищает в принципе.

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

Так я о исключениях, а не о RAII. Последний я и так всегда использую.

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

Тогда уж должность. Зарплата слабо связана со знаниями.

RazrFalcon ★★★★★
()

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

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

anonymous
()
Ответ на: комментарий от dzidzitop

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

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

- если для создания нового узла в данном (связном) списке не хватает памяти, то происходит аварийное завершение программы (вариант: вызов специального обработчика, которому передаётся исключение из деструктора).

Все это можно обеспечить, если пользоваться не просто std::exception, а nested_exception. В деструкторе нужно перед бросанием исключения проверять, std::current_exception и если он не ноль, то нужно бросаемое исключение (унаследованное от nested_exception) добавить в current. Таким образом, для собственного проекта ты можешь это реализовать (или можно вместо nested_exception реализовать свой класс исключения в котором будет указатель на следующее в списке). При вызове методов из чужих библиотек ловить их исключения, заворачивать в свои и делать throw оберток. В общем, получится примерно то, что ты хочешь по всем трем пунктам (за редкими исключениями, если, например, чужая библиотека бросает исключение и до того, как оно попадет к тебе, в ее же коде в результате еще и деструктор бросит исключение и все упадет, что по сути означает, что библиотека упала, а по причине двух исключений или SIGSEGV разница небольшая).

http://en.cppreference.com/w/cpp/error/nested_exception

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

anonymous
()
Ответ на: комментарий от lovesan

Garbage Collector, финализаторы и IDisposable+using(try with resources).

А напиши для сравнения пример с использованием этих умных слов для вот этого кода: Что отличает юниора от более продвинутого (комментарий)

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

Если речь про накладные расходы времени выполнения, то это не так. Если про понятность кода, то сильно зависит от реализации.

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

Что там умного то?

class TransactDisposable : IDisposable
{
    Action _rollback;
    bool _commit;
    
    public TransactDisposable(Action rollback)
    {
        _rollback = rollback;
    }

    public void Commit()
    {
        _commit = true;
    }

    public void Dispose()
    {
        if(!_commit)
            _rollback();
    }
};

// ...somewhere...

void AddData(string name)
{
    _activeUsers.Add(name);
    using(var tx = new TransactDisposable(() => _activeUsers.Remove(name)))
    {
        _userAppearances[name] = DateTimeOffset.Now;
        tx.Commit();
    }
}

Если речь про накладные расходы времени выполнения, то это не так. Если про понятность кода, то сильно зависит от реализации.

И то и другое - намного хуже. Я как-то давно писал, чем чревато перекладывание смартпойнтеров из одного контейнера в другой. Синтетический тест на C++ был тормознее SBCL в 10 раз примерно.

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

Синтетический тест на C++ был тормознее SBCL в 10 раз примерно

... пока тебе не напомнили про intrusive_ptr.

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

InstrusivePtr тоже тормознее. Я с этим работаю постоянно, но в форме COM и соответственно, ComPtr. https://github.com/Lovesan/SimpleAudioPlayer/blob/master/SimpleAudioPlayer/Co...

Он не подходит для хранения в куче массивов и прочего постоянного перекладывания.

Это я уж не говорю, что GC в плане менеджмента памяти, аллокации и локальности - на порядки эффективнее того что под капотом всяких new и malloc.

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

Благодарю, что-то раньше не видел nested_exception. Но вот эти «редкие исключения» и nothrow by default для деструкторов всё равно испортят всю малину. Но эти nested_exception посмотрю - может на них душа и успокоится :)

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

Что там умного то?

Спасибо за пример. Насколько я понял, он делает ровно то же и точно так же, как и окончательный вариант Жени из его сообщения (на основе которого я и просил тебя написать пример). Накладные расходы будут те же (возможно, при бросании исключения C++ будет тормозить, потому что обработка исключений в плюсах тормозит, но на то они и исключения, чтобы быть исключительно редкими).

И то и другое - намного хуже. Я как-то давно писал, чем чревато перекладывание смартпойнтеров из одного контейнера в другой. Синтетический тест на C++ был тормознее SBCL в 10 раз примерно.

Возможно, что в SBCL компилятор как-то оптимизирует умные указатели.

P.S. Неужели возвращается эпоха срачей C++ vs Lisp? С тех пор уже 3 стандарта плюсов приняли, боюсь, что CL не потянет...

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

Слово nested там должно было быть изменено на suppressed, а рекурсия - на список. А то так семантика у nested чуть иная - причинно-следственная, а не как сбор всех проблем. Тогда это было бы ближе к моим влажным мечтам про хороший raii. Но в общем в любом случае это положительное новшество.

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

Это херня. К таким областям относится только разве хард-реалтам, и то, там всякое си и ассемблер, а не кресты, по причине их недетерминированности в разных областях.

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

Т.е. я вот сейчас пишу видеостриминг, и единственная причина по которой у меня там частично что-то на крестах, и то на C++/CLI - в том, что у DirectX - COM API, а у ffmpeg - сишное. Заколебался бы биндинги писать даже для C#.

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

20-30% может и осталось старого, но для такого проекта - это фактически «с нуля».

Вы бы поосторожнее с цифрами и категоричными высказываниями. Ибо 20-30% — это уже не «полностью с нуля». А если отбросить тот код, который был добавлен в Qt4 (и чего ходить в QNetwork или QSql, того же QVector в Qt3 вроде как и не было вообще), то окажется, что эти 20-30% превращаются в 50-60-70% кода, который перекочевал из Qt3 в Qt4.

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

Это херня. К таким областям относится только разве хард-реалтам, и то, там всякое си и ассемблер, а не кресты, по причине их недетерминированности в разных областях.

Бл*ть, мастер!

  ComPtr(const ComPtr<T>& copy)
  {
    T* p = copy._p;
    _p = p;
    if(NULL != _p)
      _p->AddRef();
  }
С кодом такого качества вам еще и не такие глюки привидятся.

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

P.S. Неужели возвращается эпоха срачей C++ vs Lisp? С тех пор уже 3 стандарта плюсов приняли, боюсь, что CL не потянет...

Хахаха :-) Это цепепе не потянет :-) Убогий язычок с ещё более убогим язычком шаблонов :-) Когда видишь, как цепепешники радуются таким нововведениям как constexpr if, так аж не поймёшь, то ли жалость подкатывает, то ли смех :-) Потому как тягаться с Лиспом цепепе (с точки зрения языка) не сможет никогда :-)

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

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

C++, че поделать.

Кстати, если брать специфику COM, то конструктор копирования там не нужен, в основном, я не пользуюсь по крайней мере. Потому что там все IID_PPV_ARGS, и все такое.

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

Ну вот теперь вы перебарщиваете. 30% - ок, но не больше. Сорцы в открытом доступе.

иксперд, мля

сырцы в открытом доступе, а ты точно посчитать не смог и пруф привести

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

SObjectizer? посмотрел. занятно, но - не мое, видимо.

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

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

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

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

Дело в том, что цепепе ошибок не прощает, шаг вправо, шаг влево - и вот он SIGSEGV

Это ещё хороший расклад, относительно какого-нибудь тихого бага или даже уязвимости.

Deleted
()
Ответ на: комментарий от anonymous

ну вот например по этой теме можно сказать что тебе стоит подучить C++, чтобы общаться с ним хотя бы на равных,

Вообще-то конкретно в этой теме UVV как раз говорит предметно, т.е. о вопросах, возникающих по ходу разработки, тогда как eao197 уклоняется от этого в пользу довольно бессмысленной дискусси о терминах.

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

Речь была не о sizeof(int), а о количестве бит в байте. Я думал, что это всегда 8. Почитал Вику и понял, что таки от 1 до 48. Я не застал тез времён, когда в байте была количество бит, отличное от 8.

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

Речь была не о sizeof(int), а о количестве бит в байте.

Кому ты гоработого лепишь-то? Пройдись по ссылкам:

Если я запущу прогу с sizeof(int) собранную gcc/clang - она выдаст 4 или 2?

Я не застал тез времён, когда в байте была количество бит, отличное от 8.

Еще как застал, потому что эти времена - сейчас. Прямо сейчас, сегодня, сию же минуту.

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

для прог, который не должны падать.

Не используй исключения. Совсем.

shkolnick-kun ★★★★★
()
Ответ на: комментарий от RazrFalcon

Кто говорит о запоминании? Иди перечитай свой пост.

BruteForce ★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.