• В чем преимущества процессов над потоками?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    Главное приемущество: независимость процессов. Потоки делят между собой одну память и ресурсы системы (всякие хандлеры в винде, например).

    Если один из процессов завершится или, что чаще происходит, упадет - остальные не будут затронуты. Плюс эта независимость позволяет делать песочницы для безопасности. Так, все современные браузеры запускают js и вообще каждую вкладку в отдельном процессе. Даже если куллхацкер полностью взломает браузер через специальный сайт, он окажется в процессе, который особо прав никаких не имеет, библиотеки особо интересные туда не загружены, а все общение с внешним миром - через жестко прописанные протоколы ipc (inter-process communication). Так что злодею придется взламывать еще и их.

    Эта же независимость позволяет выполнять работу даже после завершения основного процесса. Так, если вы хотите сделать автообновятор программы, то после скачки/установки нового приложения, надо будет перезапустить основное приложение, чтобы перезаписать исполняемый файл (по крайней мере в винде). Но поток завершится вместе с программой и кто же тогда потом будет ее запускать? А вот процесс останется работать.

    Недостатки тут - ресурсоемкость. С точки зрения системы поднять и поддерживать процесс гораздо больше работы чем сделать это с потоком. Плюс упомянутое выше ipc - это лишняя работа на каждый чих.
    Ответ написан
    Комментировать
  • Как в языке си вернуть пустой массив?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    В Си у массивов нет встроенной длины*. Массив - это обычно просто указатель на область памяти, где лежат его элементы. А сколько их там, надо как-то отдельно хранить и передавать. Можно, как в строках, помечать специальным символом конец, или можно передавать длину в отдельной переменной рядом с массивом.

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

    * Исключение - статические массивы, где длина массива известна во время компиляции. Но его длину можно менять только в самом коде, поэтому тут этот случай не подходит.
    Ответ написан
    Комментировать
  • Почему вызывается приватный конструктор копирования?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Он там не вызывается. Этот приватный конструктор используется в функции
    void lib::LinkedList<T>::push(const T&) [with T = Item<int>]
    , которая в шаблоне (там где вы создаете Node* tmp). При первом обращении к этой функции компилятор пытается ее инстанциировать и натыкается на эту проблему, о чем и сообщает вам. Пока эта функция вообще никак нигде не используется - программа компилируется.

    В приведенных вами примерах вы эту функцию так или иначе трогаете разными способами.

    lib::LinkedList<Item<int>> list = lib::LinkedList<Item<int>>()
    вызвает проблему пока у вас есть virtual метод в интерфейсе, потому что это тут вызывается конструктор копирования (сначала конструктор по умолчанию для временного lib::LinkedList<Item<int>>(), а потом это все копируется в конструируемый list).

    Этот конструктор копирования должен будет также скопировать таблицу виртуальных вызовов и тут компилятору понадобится знать про запретный метод push. Похоже. Я не уверен точно, почему это проявляется именно в конструкторе копирования, где-то в недрах стандарта про это, наверняка, написано.

    Если вы напишите lib::LinkedList<Item<int>> list() - то все скомпилируется, потому что конструктор по умолчанию, видимо, не требует знания о методе push. Также удаление virtual или наследования вылечит эту проблему.

    Далее, точно по этой же причине не скомпилируется list.push(a) - это прямой вызов этой запретной функции. Если же вы напишите list.push(Item<int>()), то оно скомпилируется потому что тут вызывается push с перемещением.

    Но для исправления этого кода вам надо прежде всего избавится от этой поломанной функции push.
    Ответ написан
    3 комментария
  • Какой open source проект написан на труъ Си++?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Ну, посмотрите хотя бы хромиум. Там жесткий стиль и хоть качество кода не равномерное, в основном это точно не "Си с классами".

    Но вряд ли просмотр стороннего кода поможет вам понять, что именно коллегам не нравится в вашем коде. Тут надо все-таки коллег допытываться. Смотреть на ими написанный код.

    Если постоянные жалобы, то устройте код ревью в команде. Пусть ваш код хотя бы пару неделек кто-то постоянно будет проверять перед комитом и выдавать конкретные правки (а вообще код-ревью хорошо использовать всегда. Тот же github дает возможность это делать. Или есть опен сорсный gerrit).

    Возможно, вы используете классы только как структуры максимум с какими-то тривиальными действиями (типа get_sum, get_value, set_value и т.д.). Когда как в ООП объекты должны инкапсулировать в себе логику и уметь делать нетривиальные вещи. Сама программа должна состоять из взаимодействующих объектов.

    Еще использование stl. Стоит избегать массивов - используются std::vector. Так же вместо char* стоит использовать std::string. Ну и там куча алгоритмов есть: от выбора максимума в массиве до сортировки.
    Ответ написан
    Комментировать
  • Как получить элементы структуры?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Придется именно лазить туда и смотреть исходиник.

    Можно облегчить себе жизнь и использовать IDE. Тогда после написания "car_1." любая достаточно хорошая IDE подскажет вам список всех членов этой структуры. Но это по сути просто автоматизация действия "посмотреть в исходник".
    Ответ написан
    Комментировать
  • Как сгенеририовать СЛАУ (система линейных алгебраических уравнений) больших размеров?

    wataru
    @wataru Куратор тега Математика
    Разработчик на С++, экс-олимпиадник.
    Просто сгенерируйте случайную матрицу. Двумя циклами получайте коэффициенты через генератор случайных чисел. Вероятность, что она будет вырождена ничтожна. Потом сгенерируйте сулчайные значения всех переменных, подставьте в уравнения с имеющимеся теперь у вас коэффициентами и получите так правую часть уравнений. Вот и ваша СЛАУ с решением. Если хотите, чтобы решения не было, то можно случайно поменять правую часть в каких-то уравнениях. Если хотите, чтобы система была вырожденной, то замените какие-то строки случайной линейной комбинацией других строк (случайно получив коэффициенты линейной комбинации).

    В C++ есть генератор случайных чисел - функция rand(). Гуглите ее, она вернет случайное целое число. Если вам нужны вещественные и возможно отрицательные коэффициенты, то эти целые числа можно использовать для получения вещественных. Гуглите "C++ случайное вещественное число".
    Ответ написан
  • Сколькими ходами кубик Рубика возвращается в изначальное положение?

    wataru
    @wataru Куратор тега Математика
    Разработчик на С++, экс-олимпиадник.
    Мне кажется, формулу тут фиг выведешь и надо на компьютере эмулировать действия в цикле, пока оно назад не вернется. В группах могут быть очень сложные структуры и формулы какой-то может и не быть.
    Ответ написан
    1 комментарий
  • Как понять в коде сложность алгоритма?

    wataru
    @wataru Куратор тега Алгоритмы
    Разработчик на С++, экс-олимпиадник.
    Так или иначе придется считать количество операций. Иногда это просто, когда там тупо вложенные циклы с фиксированным количеством итераций. Иногда придется пораскинуть мозгами. Например, можно понять сколько уровней будет у рекурсивного вызова и как много операций на каждом уровне происходит. Логарифмы обычно вылезают от деления данных пополам. Когда просят сделать что-то быстрее то надо подумать а нельзя ли тут применить какую-то структуру данных. Например, можно ли BST заменить хеш таблицей.
    Ответ написан
    Комментировать
  • Как решить задачу по комбинаторике?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    Вам нужна формула размещений. От использованной формулы сочетаний отличается отсутствием k! в знаменателе.
    Ответ написан
    Комментировать
  • Как инициализировать n так что бы оно работало для всех введенных n,а не только для 2?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    Между вводом и проверкой в if-e надо поставить логическую операцию или (||).
    Ответ написан
  • В чем логическая ошибка сигсегва?

    wataru
    @wataru Куратор тега Алгоритмы
    Разработчик на С++, экс-олимпиадник.
    Проблема в том, что "214" - это строковая константа. Поэтому char *num = "214"; инициализурует указатель num адресом этой константы. Сама эта константа, видимо, лежит в read only памяти. Поэтому когда вы в алгоритме попытаетесь что-то в массив записать, программа упадет.

    Если вы внимательно почитаете вывод компилятора (желательно с ключем "-Wall"), то он вам про это выдаст варнинг:
    main.cpp:54:17: warning: ISO C++ forbids converting a string constant to ‘char*’ [-Wwrite-strings]


    Надо делать так:
    char num[] = "214";

    Ну еще у вас там в коде ошибка с непроставленным где надо +1 у index. Разворачивать надо кусок правее только что увеличенного элемента. А вы разворачиваете вместе с ним. Поэтому ваша программа еще и повиснет.

    Ну и первую перестановку ваш код не выводит.

    И последнее, вместо for (; index != -1;) лучше использовать while (index != -1)
    Ответ написан
    2 комментария
  • Как проверить n-количество или они образуют последовательность Фибоначчи?

    wataru
    @wataru Куратор тега Математика
    Разработчик на С++, экс-олимпиадник.
    Проверьте, что первый элемент равен 0.
    Проверьте, что второй элемент равен 1.
    В цикле с третьего по последний элемент проверьте, что каждый элемент равен сумме двух предыдущих.

    Если какая-то проверка где-то не сошлась - надо вывести нет. Иначе, надо вывести да.

    Удобно это делать в виде функции возвращающей булевое значение. Тогда в конце ее пишите return true. А внутри каждая проверка возвращает false, если она провалилась.
    Ответ написан
    Комментировать
  • Как найти общую формулу?

    wataru
    @wataru Куратор тега Математика
    Разработчик на С++, экс-олимпиадник.
    По идее надо бы задать формулу кусочно для разных n, но можно все собрать в одну формулу как-то так:
    (2-n)(3-n)/2*f1(n) + (n-1)(3-n)*f2(n) + (n-1)(n-2)/2*f3(n)


    Далее f1(n) = b-a+1

    Для нахождения f2 и f3 можно сдвинуть левую границу вправо до первого числа нужной четности, а правую границу - влево. Потом уже зная, что 2 крайних числа в промежутке между a' и b' берутся, то фромула будет (b'-a')/2+1.

    Для такого сдвига надо будет смотреть на четность a и b и четность n.

    В итоге:
    f2(n) = ((b-b%2)-(a+a%2))/2+1
    f3(n) = ((b-1+b%2)-(a+1-a%2))/2+1

    Можно f2 и f3 объединить используя n%2 и операцию xor: если четность a или b не такая же как у n, то надо границу сдвигать (вычесть/прибваить 1). Иначе надо вычесть/прибавить 0. xor как раз равен 1 при неравнестве и 0 при совпадении четностей.

    f23(n) = ((a+(a%2 ^ n%2))-(b-(b%2)^(n%2)))/2+1

    Итоговая формула:
    (2-n)(3-n)/2*(b-a+1) + ((n-1)(3-n) + (n-1)(n-2)/2)*(((a+(a%2 ^ n%2))-(b-(b%2)^(n%2)))/2+1)


    А еще, если пользоваться битовыми функциями, то можно вместо (n-1)(3-n) + (n-1)(n-2)/2 использовать (n & 2)/2, в вместо первой скобки (1 - (n & 2)/2)

    Формула правильно возвращает 0, если чисел в промежутке нет. Правда, она не работает, если a > b.
    Ответ написан
    Комментировать
  • Как вернуть первые N максимальных элементов из массива без сортировки массива?

    wataru
    @wataru Куратор тега Алгоритмы
    Разработчик на С++, экс-олимпиадник.
    Есть такой алгоритм. Называется quickSelect. Фактически, это обрезанный quickSort, где после выбора ведущего элемента и разбивки массива работа продолжается только в той половине, где находится раздел между первыми K элементами и остальными N-K.

    Пусть у вас N элементов в массиве и надо вернуть K минимальных. Тогда сортировка будет работать за O(N log N), а quickselect за O(N) в среднем*. В худшем случае может быть и квадратичное время работы, но этот случай практически невозможен, если реализация испольует случайные числа для выбора ведущего элемента.

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

    Суть его в том, чтобы в куче (heap aka priority queue) поддерживать пока найденные K минимальных элементов. При этом куча будет на максимум. Сначала туда кладутся первые k элементов массива, а потом каждый следующий вытесняет максимальный элемент в куче, если он его меньше.

    * Вообще говоря, можно заставить quickselect и quicksort работать идеально всегда, если использовать алгоритм Блюма-Флойда-Пратта-Ривеста-Тарьяна, который ищет медиану за O(n). Но на практике этот алгоритм не применятеся, потому что у него такая константа, что там на логарифм хватит и еще на квадрат останется.
    Ответ написан
    2 комментария
  • Как в проходе графа DFS создать массив маршурутов до нужной вершины?

    wataru
    @wataru Куратор тега Алгоритмы
    Разработчик на С++, экс-олимпиадник.
    Это вам полный перебор нужен.

    При выходе из функции очищайте пометку visited. При входе добавляйте вершину в массив/стек/список. Там будет храниться пройденный путь. При выходе из функции - убирайте последнюю вершину из пути. Если зашли в конечную вершину - выводите этот стек с вершинами.

    Еще проблемы - visited и массив пути должны быть одни на все рекурсивные вызовы. Или они должны быть глобальными или передавайте их по ссылке рекурсивно.
    Ответ написан
    2 комментария
  • Сработает ли деструктор, присвоив atomic?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Не совсем понятно, а чего вы вообще пытаетесь добиться зануляя value? После деструктора весь объект и его член value уничтожаются. Любое обращение к ним - это UB. Соотвтественно вы этот новый 0 никак снаружи пощупать не сможете.

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

    Единственный способ бороться с этим, кажется, это использовать умные указатели. Всякие WeakPtr, которые не уничтожают блок счетчиков при удалении объекта. Если же вы опустились до сырых указателей, то это тупо адрес (число). И просто по нему никак не понять, а что по этому адресу лежит - оригинальный объект или что-то левое.
    Ответ написан
  • Не работает "cin" в С++. Как исправить?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Код весьма прост и ошибки в нем не видно.
    Удостоверьтесь, что вы запускаете именно этот код. Может не ту программу закпускаете, или забыли откомпилировать.
    Удалите исполняемый файл, убедитесь что файл исходник сохранен, перекомпилируйте.
    Ответ написан
    1 комментарий
  • Какие разработчики работают с алгоритмами?

    wataru
    @wataru Куратор тега Алгоритмы
    Разработчик на С++, экс-олимпиадник.
    К сожалению, алгоритмы применяются не очень часто, а во многих областях - практически не применяются. Могу лишь сказать, что чем фундаментальнее проект, тем больше там алгоритмов.

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

    Из вашего списка скорее подходят бакенд и desktop. Еще очень алгоритмоемкая область - разработка игр. Вот там нужно много чего использовать, потому что надо все делать эффективно, иначе игра будет тормозить.

    По поводу второго вопроса, похоже большинство разработчиков алгоритмы презирают. Считают что это не нужно знать вообще и очень ненавидят алгоритмические интервью в ФААНГах и им подражающим.
    Ответ написан
    5 комментариев
  • Как запрограммировать построение мультипликативной группы по неприводимому многочлену?

    wataru
    @wataru Куратор тега Математика
    Разработчик на С++, экс-олимпиадник.
    Научитесь выполнять операции в группе. Перемножение полиномов происходит как обычно, двумя циклами, но надо потом взять по модулю многочлена, образующего группу. Тут надо будет реализовать деление столбиком.

    А дальше, чтобы найти мультипликативную группу, придется делать полный перебор. Перебирайте все полиномы (они у вас, видимо, над полем по модулю 2, их 2^n. Можно их перебирать как биты у целого числа). Потом умножайте на текущий полином в цикле, помечая в массиве уже полученные ранее полиномы. Если получили все 2^n элементов - вы нашли нужную группу. Если наткнулись на уже ранее полученный полином раньше времени - текущий кандидат не подходит.
    Ответ написан
    Комментировать
  • Будет ли большой std::vector быстрее, чем std::vectorstd::vector?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Да. Потому что локальность памяти и меньше разыменовываний.

    в vector<vector> это фактически указатель на массив указателей. Строки раскиданны по памяти как попало и при обращении к ячейке будет лишнее обращение к памяти, чтобы получить адрес строки.

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