Предлагаю делиться техническими вопросами с собеседований.
Раньше были примеры и обсуждения.
Сейчас предлагаю немного структурировать иерархически сообщения.
Есть корень — это сообщение. В детях делаем новое сообщение с заданием/решением/обсуждение:
Корень
-Набор 20 задач с финтеха
--Обсуждение
---....
-Задача на наследование с вызовом виртуальных функций из базового класса
--Обсуждение
и т.д.
Стартую своими.
Сохранял как в текстовом, так и в графическом виде. Где-то есть решения.
По поводу первого задания есть сомнения, что пункты 2 и 3 равнозначны. const указывает на константность того, что стоит слева от него, а тут в одном случае значение, а в другом указатель.
Здравствуйте, Максим, Вы писали:
A>>На решение был 1 час в домашней обстановке.
М>По поводу первого задания есть сомнения, что пункты 2 и 3 равнозначны. const указывает на константность того, что стоит слева от него, а тут в одном случае значение, а в другом указатель.
видимо, имелось в виду 3 и 1
или пункты перепутаны, потому как const T * -- указатель на кост.объект
Безумный код иногда меня ставит в тупик: A>Image: fm1.png
Вызов виртуального метода из не виртуального деструктора...
По стандарту (11.10.4/4) должен быть вызван метод A::printFromDestructor(), значит ответ: ~A, а не ~B, как ошибочно указано в комментарии.
Здравствуйте, night beast, Вы писали:
NB>видимо, имелось в виду 3 и 1 NB>или пункты перепутаны
Так ответы бывают правильные;
те, которые ожидает получить интервьюер;
те, которые даёт кандидат.
В идеале все три должны совпадать. Но так бывает не всегда.
Как я понимаю, на скриншотах avovana приводит ответы из третьей категории
Re[3]: Задача на наследование с вызовом виртуальных функций
Здравствуйте, Patalog, Вы писали:
BFE>>По стандарту (11.10.4/4) должен быть вызван метод A::printFromDestructor(), значит ответ: ~A, а не ~B, как ошибочно указано в комментарии. P>Это ж вроде UB — удаление объекта по указателю на базу, а деструктор не виртуальный?
Хмм. Действительно:
С++14
5.3.5/3
In the first alternative (delete object), if the static type of the object to be deleted is different from its dynamic type, the static type shall be a base class of the dynamic type of the object to be deleted and the static type shall have a virtual destructor or the behavior is undefined. In the second alternative (delete array) if the dynamic type of the object to be deleted differs from its static type, the behavior is undefined.
С++20
7.6.2.8/3
In a single-object delete expression, if the static type of the object to be deleted is different from its dynamic type and the selected deallocation function (see below) is not a destroying operator delete, the static type shall be a base class of the dynamic type of the object to be deleted and the static type shall have a virtual destructor or the behavior is undefined. In an array delete expression, if the dynamic type of the object to be deleted differs from its static type, the behavior is undefined.
помню позвал хр прособеседоваться в их hft ко,
делать было нечего, дай попробую
все вопросы были фигня, но на один я задумался и ответил что в голову пришло, только что бы дальше двигаться и услышать другие
вопрос с hft ко,
— есть двух мерная матрица знаковых целых чисел(кажется целых вот точно не помню этот момент)
и у нас есть алгоритм, который суммирует сначала по вертикали а потом по горизонтали складывает вертикальные суммы
и есть алгоритм который суммирует сначала по горизонтали а потом по вертикали складывает горизонтальные суммы
так вот, будет ли всегда одинаковыми эти суммы в двух алго?
я подумал что знак по идеи может прыгать и в переносе он не участвует
значит суммы могут быть разными
наверное в фин области это сакральные знания, жаль мне в моих областях(а их много) за 10+ лет не понадобились
так что увы если ошибся с ответом, но и мне правильного ответа так и не сказали
Здравствуйте, reversecode, Вы писали:
R>вопрос с hft ко, R>- есть двух мерная матрица знаковых целых чисел(кажется целых вот точно не помню этот момент) R>и у нас есть алгоритм, который суммирует сначала по вертикали а потом по горизонтали складывает вертикальные суммы R>и есть алгоритм который суммирует сначала по горизонтали а потом по вертикали складывает горизонтальные суммы
R>так что увы если ошибся с ответом, но и мне правильного ответа так и не сказали
Если с плавающей точкой, то может, т.к. точка может необратимо прыгать вперед на разряды и тогда мелкие слагаемые просто будут игнорироваться.
R>- есть двух мерная матрица знаковых целых чисел(кажется целых вот точно не помню этот момент) R>и у нас есть алгоритм, который суммирует сначала по вертикали а потом по горизонтали складывает вертикальные суммы R>и есть алгоритм который суммирует сначала по горизонтали а потом по вертикали складывает горизонтальные суммы R>так вот, будет ли всегда одинаковыми эти суммы в двух алго?
Для целых — всегда одинаковая, так как равна сумме всех элементов.
Достаточно представить себе двумерный массив как линейный по строкам.
То ли ты складываешь подряд, то ли через n — общая сумма от этого не меняется.
Для дробных, как тут уже сказали, ошибки точности могут быть из-за слишком большой разницы в числах.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Здравствуйте, LaptevVV, Вы писали:
R>>- есть двух мерная матрица знаковых целых чисел(кажется целых вот точно не помню этот момент) LVV>Для целых — всегда одинаковая, так как равна сумме всех элементов.
Это в теории, а на практике может быть UB при переполнении для знаковых целых. Пример
Здравствуйте, reversecode, Вы писали:
R>помню позвал хр прособеседоваться в их hft ко, R>делать было нечего, дай попробую
R>все вопросы были фигня, но на один я задумался и ответил что в голову пришло, только что бы дальше двигаться и услышать другие
R>вопрос с hft ко, R>- есть двух мерная матрица знаковых целых чисел(кажется целых вот точно не помню этот момент) R>и у нас есть алгоритм, который суммирует сначала по вертикали а потом по горизонтали складывает вертикальные суммы R>и есть алгоритм который суммирует сначала по горизонтали а потом по вертикали складывает горизонтальные суммы R>я подумал что знак по идеи может прыгать и в переносе он не участвует R>значит суммы могут быть разными R>наверное в фин области это сакральные знания, жаль мне в моих областях(а их много) за 10+ лет не понадобились R>так что увы если ошибся с ответом, но и мне правильного ответа так и не сказали
Ну там по горизонтали, например, может быть переполнение, а по вертикали будут соотв. отрицательные
числа. Как вариант.
А я вот задумался -- а double или float могут переполняться, или просто точность потеряют?
// Требуется реализовать класс индекса, для хранения данных по 3-м вложенным текстовым ключам
//
// index["key1"]["key2"]["key3"] = data;
//
// в последнем уровне индекса содержатся данные объект класса Data
//
// Пример заполнение данных по ключам выглядит так:
//
// Data data1, data2;
// Index idx;
// idx.set("key1").set("key2").set("key3").set(data1);
// idx.set("key1.1").set("key2.1").set("key3.1").set(data2);
//
// Пример доступа к данным по ключам:
//
// data1 = idx.get("key1").get("key2").get("key3").get();
//
// в реализации предусмотреть раcширение глубины индексовclass Data {
};
class Index {
};
int main()
{
Data data1, data2, data3;
Index idx;
// добавление в индекс
//idx.set("key1").set(data1);
idx.set("key1").set("key2").set("key3").set(data1);
idx.set("key1.1").set("key2.1").set("key3.1").set(data2);
idx.set("key1.2").set("key2.2").set("key3.2").set(data3);
// получение данных из индекса
data1 = idx.get("key1").get("key2").get("key3").get();
data2 = idx.get("key1.1").get("key2.1").get("key3.1").get();
data3 = idx.get("key1.2").get("key2.2").get("key3.2").get();
return 0;
}
Здесь не совсем понял что надо сделать.
Может парсер typescript? Тогда почему такие же С++ классы уже есть в файлах?
Зачем что-то с чем-то связывать внутри биндингами?
Есть уже заготовленный регистратор объектов.
Была идея:
1. Парсить *.ts файл с описанием классов
2. Разбивать на токены(ни разу не делал. Что это даёт? Разные сущности?)
3. Получать что-то
4. Это что-то зачем-то связывать с уже готовыми такими же С++ классами.
5. Вывести в стиле рефлексии
А как вы считаете, что хотят и как этого добиться?
Нормально. Если за час не смогли загуглить решения к тем, что не помнят назубок, — вполне годится в качестве проверки.
Непонятно, правда, что именно проверяется. Если б вопрос стоял как "в каком случае лучше использовать const/.../..., для решения каких проблем придуман volatile, и решает ли он эти проблемы" — оно как-то логичнее было бы, что ли.
Получается есть набор С++ классов под стать классам из *.ts файла.
На входе *.ts файл может менять. В нём могут быть данные классы в разной последовательности.
Суть программы — получая такой *.ts файл выводить такой же.
Сделать это через связывание уже готовых С++ классов.
Гарантируется что в *.ts файле могут быть только классы, которые уже подготовлены в С++ исполнение.
Алгоритм программы вкратце:
Комбинация ts классов -> выставление соответствия из уже готовых С++ файлов -> вывод.
В репе есть пример как это делать вручную.
А как автоматизировать?
Наверное:
1. Считать входной *.ts файл.
2. Выцепить названия классов
3. Поместить их в контейнер
4. Пройтись по контейнеру
5. получая очередное имя создавать биндинг, в котором еще в зависимости от имени проставляется тип:
Binder<MarketPolicy> binder("MarketPolicy");
Таким образом получим контейнер биндеров. Что с ними делать?
6. Поместить в некий ObjectRegistry
7. Вызвать метод render()
Не всё понятно. Не понятна наводка что за проставление свойств у такого биндинга, если вдруг у класса есть поля:
Здравствуйте, Максим, Вы писали:
М>Это в теории, а на практике может быть UB при переполнении для знаковых целых. Пример
Переполнение знаковых целых это UB? Я-то думал, что на практике все целочисленные вычисления, хоть с переполнением, хоть без, выполняются по модулю 2^32 или 2^64.
https://en.cppreference.com/w/cpp/language/ub
undefined behavior — there are no restrictions on the behavior of the program. Examples of undefined behavior are data races, memory accesses outside of array bounds, signed integer overflow, null pointer dereference, more than one modifications of the same scalar in an expression without any intermediate sequence point (until C++11)that are unsequenced (since C++11), access to an object through a pointer of a different type, etc. Compilers are not required to diagnose undefined behavior (although many simple situations are diagnosed), and the compiled program is not required to do anything meaningful.
В общем, всё свелось к тому, что надо вывести тип в шаблонном методе и записать его строкой исходя из такой странной записи передачи поля класса по ссылке &LimitPolicy::price:
К примеру, класс:
struct LimitPolicy {
double price;
std::optional<double> stop;
};
Метод:
template <typename Attribute>
void set(std::string name, Attribute attribute){
// <----- получить std::string от Attribute
};
И вот как передают поле:
set("price", &LimitPolicy::price);
Надо внутри set записать тип переданного поля в строку
Понятно, спасибо. В описание просили только плюсы использовать. Предпочтительно С++17.
Т.е. узнать тип можно только в рантайм?
И что это за ссылка на поле класса? До этого примера такого нигде не встречал.
Base* b = (rand() % 2 == 0) ? new Derived1 : new Derived2;
report(typeid(*b));
конкретный тип принципиально не будет известен без выполнения программы. typeid и нужен для выяснения динамического типа, который неизвестен во время компиляции. Ну и ещё для пары сценариев: для type_index и для отладочной печати из макросов/шаблонов (самое полезное!).
И главное: typeid для этой задачи использовать не надо.
В общем случае он не позволит её решить, а частные случаи будут либо бесполезны с практической точки зрения (например, предварительная регистрация всех возможных комбинаций поддерживаемых type_index), либо очень сложны и непереносимы (вроде запуска name-demangle над typeid(f).name() и анализа результатов).
Эта задача совсем на другое: на написание кода, который умеет доставать из шаблонного аргумента типы, которые он содержит, и который умеет сопоставлять его с другими стандартными шаблонами (вроде std::optional, std::variant), чтобы преобразовать последние в соответствующие typescript-конструкции.
A>И что это за ссылка на поле класса? До этого примера такого нигде не встречал.
Нет тут ссылок. В этом контексте — это взятие адреса. На выходе — обычный pointer to (data) member.
Его тип как раз содержит всё что нужно: и тип поля, и тип класса, в котором это поле находится.
// Требуется реализовать класс индекса, для хранения данных по 3-м вложенным текстовым ключам
//
// index["key1"]["key2"]["key3"] = data;
//
// в последнем уровне индекса содержатся данные объект класса Data
//
// Пример заполнение данных по ключам выглядит так:
//
// Data data1, data2;
// Index idx;
// idx.set("key1").set("key2").set("key3").set(data1);
// idx.set("key1.1").set("key2.1").set("key3.1").set(data2);
//
// Пример доступа к данным по ключам:
//
// data1 = idx.get("key1").get("key2").get("key3").get();
//
// в реализации предусмотреть раcширение глубины индексовclass Data {
};
class Index {
};
int main()
{
Data data1, data2, data3;
Index idx;
// добавление в индекс
//idx.set("key1").set(data1);
idx.set("key1").set("key2").set("key3").set(data1);
idx.set("key1.1").set("key2.1").set("key3.1").set(data2);
idx.set("key1.2").set("key2.2").set("key3.2").set(data3);
// получение данных из индекса
data1 = idx.get("key1").get("key2").get("key3").get();
data2 = idx.get("key1.1").get("key2.1").get("key3.1").get();
data3 = idx.get("key1.2").get("key2.2").get("key3.2").get();
return 0;
}
Здравствуйте, reversecode, Вы писали:
R>не боитесь что компании могут сильно обидится и начать бороться с тем что вы выставляете годами вымученные тестовые задание-вопросы ?
Ну да, это к тому, что:
1) Ок для соискателя, если человеку дали вопросы, он погуглил, нашел эту тему — старается.
2) Ок для компании, что если пару лет были одни и теже вопросы, можно придумать что-то новенькое.
R>а очень разносторонние девелоперы, вообще он хот знание не держат в голове, иначе сума сойдут
Хорошее замечание. Последнее время спрашиваю вопросы и материалы для подготовки. Что интересно — hr'ы говорят. Им дают обратную связь кандидаты или сами компании могут нормально к этому относится и сами советуют. Мне сейчас по postgresql посоветовали по конкурентную запись почитать, индексы и т.п. для следующего этапа.
3 этапа:
1. Создать поле. Расставить бомбы
2. Расставить цифры, которые говорят, сколько бомб вокруг
3. Кликнуть по полю, получить результат:
а) Пустое место. Открываются все пустые рядом и пустые рядом с ними и т.д.
б) Цифра
в) Бомба
Сделал 2 этапа:
int x, y, bombs;
//======================
vector<vector<int>> table;
table.resize(x);
for(auto & col: table)
col.resize(y);
// 9 == bomba
// 0 == emptyfor (int i = 0; i < bombs; ++i) {
int row = srand(time_now()) % x;
int col = srand(time_now()) % y;
if(table[col][row] == 9) {
--i;
continue;
}
table[col][row] = 9;
}
//======================for(int col = 0; col < x; ++col) {
for(int row = 0; row < y; ++row) {
if(table[col][row] == 9)
continue;
/*
col - 1, row
col + 1, row
col , row - 1
col , row + 1
col , row
col - 1, row - 1
col + 1, row - 1
col - 1, row + 1
col + 1, row + 1
*/int bombs_around = 0;
int cols[] = [col - 1, col, col + 1];
int rows[] = [row - 1, row, row + 1];
for(int l = 0; l < 3; ++l) {
for(int k = 0; k < 3; ++k) {
if(cols[l] < 0 || cols[l] > x - 1 || rows[k] < 0 || rows[k] > y - 1)
continue;
if(table[cols[l]][rows[k]] == 9)
bombs_around++;
}
}
table[col][row] = bombs_around;
}
что то не припомню что бы мне что то посоветовали хоть раз перед собеседованием
причем несколько последних раз я сам несколько раз хр спросил, что будут спрашивать, и к чему готовится
проигнорили мой вопрос
вообщем я всегда собеседуюсь не готовясь
// написать функцию replace c 3-мя входными аргументами, возвращающую новую строку
//
// список аргументов:
// 1 - входная строка
// 2 - что ищем во входной строке
// 3 - чем заменяем
//
// примеры выполнения:
// replace("aabbcc", "b", "B") -> "aaBBcc"
// replace("aabbcc", "bb", "B") -> "aaBcc"
// replace("aabbbcc", "bb", "B") -> "aaBbcc"
// replace("aabbcc", "b", "BB") -> "aaBBBBcc"
std::string replace(std::string input, std::string substr, std::string replace_to) {
std::string res;
int idx_of_substr = 0;
ind end_idx_copied = 0;
for(int i = 0; i < input.size(); ++i) {
idx_of_substr = input.find(substr, idx_of_substr);
if(idx_of_substr != std::string::npos) {
res.append(input.substr(end_idx_copied, idx_of_substr));
res.append(replace_to);
i = i + substr.size() - 1;
end_idx_copied = i;
}
}
res.append(input.substr(end_idx_copied, input.size() - 1));
}
Сначала сам стал пытаться реализовать поиск substr. Подсказали, что можно взять готовую.
Успел основное решение. Еще краевой случай, чтобы индекс не вышел за границу.
Тестовое задание.
В данной задаче будут рассматриваться 13-ти значные числа в тринадцатиричной системе исчисления(цифры 0,1,2,3,4,5,6,7,8,9,A,B,C) с ведущими нулями.
Например, ABA98859978C0, 6789110551234, 0000007000000
Назовем число красивым, если сумма его первых шести цифр равна сумме шести последних цифр.
Пример:
Число 0055237050A00 — красивое, так как 0+0+5+5+2+3 = 0+5+0+A+0+0
Число 1234AB988BABA — некрасивое, так как 1+2+3+4+A+B != 8+8+B+A+B+A
Задача:
написать программу на С/С++ печатающую в стандартный вывод количество 13-ти значных красивых чисел с ведущими нулями в тринадцатиричной системе исчисления.
В качестве решения должен быть предоставлено:
1) ответ — количество таких чисел. Ответ должен быть представлен в десятичной системе исчисления.
2) исходный код программы.
Это задача на перестановки(permutation) с повторами. К примеру, есть пин код.
Может быть цифра 1-9 в любой из 4ёх позиций. Причём, не так, что раз 1 уже была, то её нельзя поставить в другую позицию. Может быть код и 1111.
Т.е. сами цифры могут повторяться.
Есть формула. Там учитывается:
1) кол-во возможных чисел. Здесь 13ть
2) кол-во мест для перестановки. Здесь 6
Шаги:
1. Находим для каждой суммы кол-во возможных комбинаций
2. Допустим, для суммы 39 есть 195042 возможных комбинаций цифр.
Это в левой части. И в правой, получается, тоже 195042.
К примеру, ССС000, 000ССС, 0С0С0С (если бы было всего 3 возможных сочетаний цифр, которые дают сумму 39)
Теперь нужно по каждой такой сумме найти кол-во сочетаний:
1 ССС000 = ССС000
2 ССС000 = 000ССС
3 ССС000 = 0С0С0С
4 000ССС = ССС000
5 000ССС = 000ССС
6 000ССС = 0С0С0С
7 0С0С0С = ССС000
8 0С0С0С = 000ССС
9 0С0С0С = 0С0С0С
Сейчас просто смотрим по той формуле, что есть цифра 3. 3 уникальных сочетания с каждой из 2ух сторон.
Сделал. Ответ оказался неверным. Может, найдёте ошибку?
Здравствуйте, reversecode, Вы писали:
R>что то не припомню что бы мне что то посоветовали хоть раз перед собеседованием R>причем несколько последних раз я сам несколько раз хр спросил, что будут спрашивать, и к чему готовится R>проигнорили мой вопрос R>вообщем я всегда собеседуюсь не готовясь
Сейчас, похоже, всё больше скатывается к ФААНГ стилю:
1) Порешай алгоритм
2) Построй систему
3) Пообщаемся
В Яндекс такое, наверное, давно. Сейчас Тиньков подъехал. 2 года назад еще не было. Сейчас ввели.
Недавно на собеседовании решал очень похожую, но с дополнительным наворотом в виде "аргументы 2 и 3 взаимозаменяемы" — надо заменять тот, что нашел первым на противоположный.
Здравствуйте, watchmaker, Вы писали:
W>Нет тут ссылок. В этом контексте — это взятие адреса. На выходе — обычный pointer to (data) member. W>Его тип как раз содержит всё что нужно: и тип поля, и тип класса, в котором это поле находится.
Да, спасибо. Получилось разобраться. Тип дан. Через _PRETTY_FUNCTION_ можно его получить и распарсить.
A>Тестовое задание.
A>В данной задаче будут рассматриваться 13-ти значные числа в тринадцатиричной системе исчисления(цифры 0,1,2,3,4,5,6,7,8,9,A,B,C) с ведущими нулями.
A>Например, ABA98859978C0, 6789110551234, 0000007000000
A>Назовем число красивым, если сумма его первых шести цифр равна сумме шести последних цифр.
Есть мнение, что не стоит увлекаться алгоритмическими задачами на собеседованиях — они интересные, но составляют малую часть работы и плохо говорят об способностях писать хороший код. Который должен быть понятным, поддерживаемым, переиспользуемым, и т.п. Но тут получилось прямо исключение: отлично продемонстрировано, что плохо всё
Глобальные переменные.
Ладно бы в них хранилось какое-то глобальное состояние, но нет: сугубо локальные счётчики.
Будет это работать, если запустить два потока? — Нет, они перезатрут друг-друга.
Будет это работать, если запустить функцию ещё раз? — Нет, от предыдущей итерации остался мусор.
Что-то подобное встречается в олимпиадном/спортивном программировании, где есть гарантии, что код сразу будет выкинут. Но это недостаток подобных кандидатов, что они пишут одноразовый код (впрочем следующий пункт говорит против наличия олимпиадной подготовки).
Безумный способ умножения чисел:
Написан фрагмент
unsigned long long counter = 0;
void permutations(int n, int lenght) {
if (lenght == 1) {
for (int j = 0; j < n; j++)
counter++;
} else {
for (int i = 0; i < n; i++)
permutations(n, lenght - 1);
}
}
///
{
permutations(unique_numbers, 2);
// ...
pretty_numbers += counter;
counter = 0;
}
— умножение за время O(1). И без всякого глобального счётчика.
Граничные условия и рекурсия
Даже если считать, что рекурсия тут нужна, то видно, что нет сноровки в работе с граничными случаями.
Зачем-то обрабатывается случай (lenght == 1) и не обрабатывается случай равенства нулю.
Который не только нужен для всеобщности, но позволяет не делать в обоих ветках одинаковые действия.
В функции permutations повторяется блок for (int i = 0; i < n; i++), а в функции count_sums уже целая секция
for (int j = 0; j < n; j++) {
int current = str[j] - 48;
if(current >= 10)
current = current - 7;
Зачем? Это же...
Копипаста.
Даже если предположить, что вышеприведённые одинаковые фрагменты нужны, а не возникли из-за неправильного использования рекурсии, то почему они сделаны копированием? Почему это не функции с понятными именами?
Магические константы.
Тут нулевая поддерживаемость:
for (int j = 0; j < n; j++) {
int current = str[j] - 48;
if(current >= 10)
current = current - 7;
sum_numbers[sum + current]++;
}
Откуда 48? почему 10? зачем 7?
И как ты всё это предлагаешь обобщать на систему счисления основанием не 13, а 313, например?
Не говоря уж о том, что если считать, что этот фрагмент нужен, то короче, понятнее и универсальные он записывается так:
Собственно, насколько удобно код использовать для решения похожих задач? Посчитать число счастливых автобусных билетов или оценить число коллизий в наивной хэш-функции?
В программе есть один параметр: int lenght = 6; — размер левой или правой половины. Но как задать число цифр в середине? Или изменить основание системы счисления?
Вот это, кстати, жесть:
Ну какая разница какими там буквами или цифрами что записывается?
Почему если я тут изменю ABC на АБВ, то программу разнесёт?
Алгоритм.
Архимедленное умножение через рекурсию и инкремент выше уже видели. Но и способ подсчёта числа способов набрать заданную сумму ему не уступает. Тоже инкременты. А если понадобится 13 заменить на 20, то сколько это работать будет? Даже если не выписывать комбинаторную формулу, то уж динамическим программированием можно за O(Base*Length) посчитать вместо O(BaseLength) в текущем варианте.
Тестирование и краевые случаи.
Выше ты говоришь, что ответ получился неправильный. А почему ты сам не протестировал программу?
Не на каких-то там больших числах, а на самых простых примерах.
Например, сколько есть красивых чисел длиной 1 в унарной системе счисления? Программа выдаёт ответ, что немногим больше 18 квинтиллионов? Ладно, это по модулю 264 получилось. Без него всего-лишь количество чисел выходит отрицательным — похож какой-либо их этих ответов на правильный?
Я бы предложил проверить программу на ещё более простом примере: сколько есть красивых числе длины 0, — но у тебя она упадёт с переполнением стека (к вопросу об универсальности и обработке граничных условий).
Последнее довольно печально: как можно писать код и не проверить его в уме хотя бы на игрушечных примерах?
На фоне этих проблем уже кажется мелочами другие небрежности:
В исходнике оставлен закоментированный код (и это не поясняющий пример из документации);
В именах опечатки (lenght);
Нет const для обозначения неизменяемых параметров;
Просили вывести число — а программа зачем-то выводит портянку ещё чего-то непонятного; Для хранения плотного набора чисел c индексами от 0 для Length*Base прямо-таки напрашивается вектор, а не map. Но сойдёт, если сказать что это для экономии строчек кода (меньше кода — меньше мест для ошибки), да и будет работать не так уж медленно, если убрать из кода бесконечные инкременты.
миль пардон
но всегда относился и буду относиться к задачам на собеседовании
как к задачам у которых одна цель — показать правильный выполняемый результат
и никогда не буду тратить время, >Который должен быть понятным, поддерживаемым, переиспользуемым, и т.п.
просто потому что время дорого, а мне за него не платят
да и не помню что бы хоть кто то когда то ставил вообще такие требования на собеседования
соответственно что бы критиковать или делать вердикт про, но хире по этим критерием
надо было их предварительно в постановке задаче все обозначить
а то в прям таки вспоминается одна известная бюргерская ко
которая в былые времена лет 6 назад, любила давать задачку на дописать имплементацию функции на добавление в контейнер значения с проверкой за границы
и потом отписывала что конечно же — "вы нам не подходите"
Здравствуйте, watchmaker, Вы писали:
W>Последнее довольно печально: как можно писать код и не проверить его в уме хотя бы на игрушечных примерах?
Спасибо за развёрнутую обратную связь! Действительно, делал напором, чтобы быстрее получить результат. Это было тех задание на дом. Не хотелось много времени тратить.
Для меня прорыв был в том смысле, что пару лет назад я встречал такую задачу и вообще не смог понять, что делать.
Сейчас порадовался, что:
1) Понял принцип
2) Взялся за код
3) Получил output
Следующий этап — осмысление. Благодаря вашей обратной связи смогу качественней осмыслить пример. Будет время, желание, переделаю. Может, еще раз отошлю hr'у.
Re[4]: Задача на наследование с вызовом виртуальных функций
BFE>>>По стандарту (11.10.4/4) должен быть вызван метод A::printFromDestructor(), значит ответ: ~A, а не ~B, как ошибочно указано в комментарии. P>>Это ж вроде UB — удаление объекта по указателю на базу, а деструктор не виртуальный? BFE>Хмм. Действительно
Какой опыт кодинга на цепепе?
Re[2]: Задача на наследование с вызовом виртуальных функций
BFE>Безумный код иногда меня ставит в тупик: A>>Image: fm1.png BFE>Вызов виртуального метода из не виртуального деструктора...
Чем-то отличается от вызова виртуального метода из виртуального деструктора?
(Это безотносительно UB при удалении).
Re[5]: Задача на наследование с вызовом виртуальных функций
Здравствуйте, σ, Вы писали:
BFE>>>>По стандарту (11.10.4/4) должен быть вызван метод A::printFromDestructor(), значит ответ: ~A, а не ~B, как ошибочно указано в комментарии. P>>>Это ж вроде UB — удаление объекта по указателю на базу, а деструктор не виртуальный? BFE>>Хмм. Действительно σ>Какой опыт кодинга на цепепе?
29 лет. А что?
И каждый день — без права на ошибку...
Re[3]: Задача на наследование с вызовом виртуальных функций
Здравствуйте, σ, Вы писали:
BFE>>Безумный код иногда меня ставит в тупик: A>>>Image: fm1.png BFE>>Вызов виртуального метода из не виртуального деструктора... σ>Чем-то отличается от вызова виртуального метода из виртуального деструктора?
Возможно, что да, так как производный объект не был разрушен, значит члены производного объекта ещё существуют. На старых компиляторах такой код приводил к утечкам памяти, если у производного классы были члены заказывавшие память в куче. Конкретно этот код отработал бы без проблем и распечатал бы ~B. Более то, у MS компилятора были опции (может и сейчас есть) регулирующие время конструирования таблиц виртуальных методов: можно было сконструировать все таблицы виртуальных методов до создания объекта и тогда вызов виртуального метода в конструкторе приводил к вызову метода ещё несконструированного объекта, а в деструкторе к вызову метода уже разрушенного объекта. В данном коде объект B не разрушен, так что код может отработать без проблем, а так как значение указателя на базовый и производных класс в данном случает совпадает, то и освобождение памяти может отработать корректно, без утечек (из-за отсутствия членов у класса B). В современных компиляторах раз на раз не приходится и предсказать результат UB невозможно. В любом случае, если такой безумный код на собеседовании, то надо быть готовым к низкой культуре программирования.
И каждый день — без права на ошибку...
Re[4]: Задача на наследование с вызовом виртуальных функций
BFE>>>Безумный код иногда меня ставит в тупик: A>>>>Image: fm1.png BFE>>>Вызов виртуального метода из не виртуального деструктора... σ>>Чем-то отличается от вызова виртуального метода из виртуального деструктора? BFE>Возможно, что да, так как производный объект не был разрушен…
Я имел в виду в случае, когда UB нет.
Re[4]: Задача на наследование с вызовом виртуальных функций
у MS компилятора были опции (может и сейчас есть) регулирующие время конструирования таблиц виртуальных методов: можно было сконструировать все таблицы виртуальных методов до создания объекта и тогда вызов виртуального метода в конструкторе приводил к вызову метода ещё несконструированного объекта, а в деструкторе к вызову метода уже разрушенного объекта.
какая то дичь, реверсил код который генерил еще 5 версия компилера msvc, т.е. уж очень древняя версия
и в мс ничего в инициализации виртуальных методов не менялось никогда
чуть по другому было в гцц старых около 3 версии
там виртуальная таблица была толще, потому что у них pfn занимал 8 байт даже на 32битах, сейчас она стала такой же как и в msvc
т.е 4 байта на 32 бита, 8 на 64 бита
а так таблицы уже все готовы, только указатель на них устанавливается в начале инициализации очередного конструктора
Re[5]: Задача на наследование с вызовом виртуальных функций
Здравствуйте, reversecode, Вы писали:
R>какая то дичь, реверсил код который генерил еще 5 версия компилера msvc, т.е. уж очень древняя версия R>и в мс ничего в инициализации виртуальных методов не менялось никогда
Не самих таблиц, а таблиц с точки зрения объекта.
R>а так таблицы уже все готовы, только указатель на них устанавливается в начале инициализации очередного конструктора
Ну да. И вот указатель на таблицу можно установить заранее, а не менять в конструкторах.
PS Скорее всего это опция включала или выключала __declspec(novtable) атрибут через какой-нибудь дефайн, но это было так давно, что точно не скажу.
Здравствуйте, avovana, Вы писали:
A>Требуется реализовать функцию zip, которая соединяет элементы двух слайсов в слайс пар
Подозреваю, что хотели увидеть не просто перекладывание из контейнера в контейнер, а виртуальный контейнер, в духе std::ranges::zip_view (по возможности, без копирования).
Примерно так:
#include <iostream>
#include <algorithm>
#include <tuple>
#include <iterator>
#include <ranges>
#include <string>
#include <vector>
#include <list>
#include <map>
#include <utility>
#include <cassert>
template< typename T >
struct container_traits
{
using iterator = decltype( std::begin( std::declval<T>() ) );
using value_type = typename std::iterator_traits< iterator >::value_type;
using reference_type = typename std::iterator_traits< iterator >::reference;
using container = T;
};
template< typename T >
struct container_traits< std::reference_wrapper<T> >
{
using iterator = typename container_traits<T&>::iterator ;
using value_type = typename container_traits<T&>::reference_type;
using reference_type = value_type;
using container = T&;
};
template< typename T1, typename T2 >
class zip : std::pair< typename container_traits<T1>::container ,
typename container_traits<T2>::container >
{
using base = std::pair< typename container_traits<T1>::container ,
typename container_traits<T2>::container >;
using _iterator_1 = typename container_traits<T1>::iterator;
using _iterator_2 = typename container_traits<T2>::iterator;
using _value_type_1 = typename container_traits<T1>::value_type;
using _value_type_2 = typename container_traits<T2>::value_type;
public:
using base::base;
using value_type = std::pair< _value_type_1, _value_type_2 >;
class iterator : public std::pair< _iterator_1, _iterator_2 >
// for C++14 and older:
// ,public std::iterator< std::input_iterator_tag, vlaue_type >
{
using base = std::pair< _iterator_1, _iterator_2 >;
public:
using base::base;
iterator operator++() { return { first++, second++ }; }
iterator operator++(int) {return { ++first, ++second }; }
bool operator == ( const iterator& r ) const { return static_cast<const base&>(*this) == r; }
bool operator != ( const iterator& r ) const { return static_cast<const base&>(*this) != r; }
vlaue_type operator*() const { return { *first, *second }; }
};
using const_iterator = iterator;
size_t size() const { return std::min( std::size(first), std::size(second) ); }
value_type operator[]( size_t index ) const { return { first[index], second[index] }; }
value_type at( size_t index ) const { return { first.at(index), second.at(index) }; }
iterator begin() const { return { first.begin(), second.begin() }; }
iterator end () const { return { first.end (), second.end () }; }
};
template< typename T1, typename T2 >
zip(T1,T2) -> zip<T1,T2>;
using namespace std;
int main()
{
auto i = zip( std::vector{1,2,3}, std::vector{"a"s, "b"s, "c"s} )[1];
assert( ( i==std::pair{2,"b"s} ) );
// support of conteiner with no 'operator[]'auto j= * std::begin( zip( std::list{1,2,3}, std::list{"a"s, "b"s, "c"s} ) );
assert( ( j==std::pair{1,"a"s} ) );
// TODO: support of std::initializer_list
// auto p = * std::begin( zip( {1,2,3}, {"a"s, "b"s, "c"s} ) );
// assert( ( p==std::pair{1,"a"s} ) );
// test 'size'
assert( zip( std::vector{1,2,3}, std::vector{"a"s, "b"s, "c"s, "d"s} ).size() == 3 );
// test for-each loopfor( auto i : zip( std::vector{1,2,3}, std::vector{"a"s, "b"s, "c"s} ) )
std::cout << i.first << " " << i.second << std::endl;
// modification via reference:
std::vector<int> a={1,2,3,4,};
std::vector<int> b={1,2,3,4,};
zip(std::ref(a),std::ref(b))[1] = std::pair{ 5,6 };
assert( a[1] == 5 );
assert( b[1] == 6 );
return 0;
}
Re[6]: Задача на наследование с вызовом виртуальных функций
BFE>>>>>По стандарту (11.10.4/4) должен быть вызван метод A::printFromDestructor(), значит ответ: ~A, а не ~B, как ошибочно указано в комментарии. P>>>>Это ж вроде UB — удаление объекта по указателю на базу, а деструктор не виртуальный? BFE>>>Хмм. Действительно σ>>Какой опыт кодинга на цепепе? BFE>29 лет. А что?
Не возраст, а опыт в C++.
Re[7]: Задача на наследование с вызовом виртуальных функций
Здравствуйте, σ, Вы писали:
BFE>>>>>>По стандарту (11.10.4/4) должен быть вызван метод A::printFromDestructor(), значит ответ: ~A, а не ~B, как ошибочно указано в комментарии. P>>>>>Это ж вроде UB — удаление объекта по указателю на базу, а деструктор не виртуальный? BFE>>>>Хмм. Действительно σ>>>Какой опыт кодинга на цепепе? BFE>>29 лет. А что? σ>Не возраст, а опыт в C++.
А это и есть опыт: начинал на MS-DOS + Borland Turbo C++. Но это С++, а на C я ещё перфоленты застал (это после Фортрана и перфокарт). Но к чему все эти вопросы?
И каждый день — без права на ошибку...
Re[8]: Задача на наследование с вызовом виртуальных функций
Здравствуйте, kaa.python, Вы писали:
KP>Недавно на собеседовании решал очень похожую, но с дополнительным наворотом в виде "аргументы 2 и 3 взаимозаменяемы" — надо заменять тот, что нашел первым на противоположный.
По sql сейчас почитал по запросам.
Такое придумал. Насколько правильно?
select firstname.user, sku.purchase from user, purchase // Показываю столбцы
where id.user=user_id.purchase // объединенные кросс join'ом. Показываю лишь те строки, у которых id из этих столбцов равны
and
purchase.date between 2021-02-01 and 2021-02-27 // причем покажу только строки в которых значение даты купленного товара из интервала
and
where not id.user in (select user_id.ban_list from ban_list) // уберу такие, у которых id.user из списка, который получил вложенным подзапросом
A>Тестовое задание.
A>В данной задаче будут рассматриваться 13-ти значные числа в тринадцатиричной системе исчисления(цифры 0,1,2,3,4,5,6,7,8,9,A,B,C) с ведущими нулями.
A>Например, ABA98859978C0, 6789110551234, 0000007000000
A>Назовем число красивым, если сумма его первых шести цифр равна сумме шести последних цифр.
A>Пример:
A>Число 0055237050A00 — красивое, так как 0+0+5+5+2+3 = 0+5+0+A+0+0
A>Число 1234AB988BABA — некрасивое, так как 1+2+3+4+A+B != 8+8+B+A+B+A
A>Задача:
A>написать программу на С/С++ печатающую в стандартный вывод количество 13-ти значных красивых чисел с ведущими нулями в тринадцатиричной системе исчисления.
A>В качестве решения должен быть предоставлено:
A>1) ответ — количество таких чисел. Ответ должен быть представлен в десятичной системе исчисления.
A>2) исходный код программы.
from functools import cache
nums = (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)
@cache
def num_ways(n, depth, numbers):
if n < 0:
return 0
if depth == 0:
return 1 if n == 0 else 0
ans = 0
for number in numbers:
ans += num_ways(n-number, depth-1, numbers)
return ans
count = 0
for s in range(0, 73):
cnt = num_ways(s, 6, nums)
print(s,' ', cnt)
count += cnt*cnt
print(count)
Здравствуйте, reversecode, Вы писали:
R>так и хочется посмотреть в глаза комитету R>что же это за уб по стандарту, если все существующие компиляторы выдают один и тот же результат
Не вижу ничего удивительного в том, что в некоторых частных случаях UB совпадает с интуитивно ожидаемым поведением.
Я бы поинтересовался почему не S* s = new(storage) S("hello world"); вместо последних двух строк и в чём разница с дальнейшим использованием s (слева) в s->s.
Re[12]: Задача на наследование с вызовом виртуальных функций
здесь надо углубляться в саму суть проблемы и почему по стандарту это уб?
это из той же серии почему до сих пор ++i + i++ уб ?
комитет не может определиться как обходить дерево?
и тогда на вопрос при собеседовании — что выведет тот код с не виртуальными деструкторами использующие виртуальные методы
вы вы как практикующий программист с пруфами на все существующие компилеры скажете ?
>from A >the end
хотя вопрос будет наверняка провокационным и задающий будет ожидать ответа — уб
и я в +100500 раз бы повторил, лавер с++ != программист с++
этот точно так же как гражданин страны не обязан знать наизусть все законы той страны где он проживает,
иначе юристы бы померли от голода
R>здесь надо углубляться в саму суть проблемы и почему по стандарту это уб?
Ответ очень простой: а почему должно быть не UB? "Потому что все известные мне реализации ведут себя одинаково" это не ответ.
Re[13]: Задача на наследование с вызовом виртуальных функций
Здравствуйте, reversecode, Вы писали:
R>здесь надо углубляться в саму суть проблемы и почему по стандарту это уб?
Потому, что после delete мы имеем объект частично разрушенный. После этого ничего разумного с таким объектом сделать не можно.
R>это из той же серии почему до сих пор ++i + i++ уб ?
Это потому, что ++i и i++ могут выполнятся параллельно. Теоретически (но это пока).
R>комитет не может определиться как обходить дерево?
Не в этом дело.
R>и тогда на вопрос при собеседовании — что выведет тот код с не виртуальными деструкторами использующие виртуальные методы R>вы вы как практикующий программист с пруфами на все существующие компилеры скажете ?
Да как обычно: этот код следует переписать, так как он не соответствует общепринятой практике. Любой инструмент проверки кода укажет, что деструктор в данном случае должен быть виртуальным.
>>from A >>the end R>хотя вопрос будет наверняка провокационным и задающий будет ожидать ответа — уб
Ну..., я сразу назвал код безумным.
R>и я в +100500 раз бы повторил, лавер с++ != программист с++ R>этот точно так же как гражданин страны не обязан знать наизусть все законы той страны где он проживает, R>иначе юристы бы померли от голода
Тут ведь как: незнание законов не освобождает от ответственности.
И каждый день — без права на ошибку...
Re[6]: Задача на наследование с вызовом виртуальных функций
Здравствуйте, Kolesiki, Вы писали:
K>Вы страшный человек! Кодить на сипипях, имея уже лет как 20 C#, это надо очень сильно себя не любить.
Ха! Текущий проект в котором я работаю (и который уже в эксплуатации), это переписывание с C# на С++. Это всё из-за того, что в MS не предполагают продлевать поддержку Windows CE. В результате огромное количество всякого встроенного будет переведено на Debian + QT.
Здравствуйте, avovana, Вы писали:
A>// Как сделать чтобы робот шагал сначала левой, потом правой, левой, правой...? A>// Обобщить до 40жки, чтобы каждая нога двигалась за предыдущей A>===========
Скрытый текст
A>
A>int main()
A>{
A> std::thread first([]()
A> {
A> while(true)
A> {
A> std::cout << "First" << std::endl;
A> }
A> }
A> );
A> std::thread second([]()
A> {
A> while(true)
A> {
A> std::cout << "Second" << std::endl;
A> }
A> }
A> );
A> first.join();
A> second.join();
A> return 0;
A>}
A>
σ>Я бы поинтересовался почему не S* s = new(storage) S("hello world"); вместо последних двух строк и в чём разница с дальнейшим использованием s (слева) в s->s.
А она (разница) есть? storage не выровнен => s — unspecified. Разве нет?
σ>>Я бы поинтересовался почему не S* s = new(storage) S("hello world"); вместо последних двух строк и в чём разница с дальнейшим использованием s (слева) в s->s.
BFE>А она (разница) есть? storage не выровнен => s — unspecified. Разве нет?
Выравнивание… Ну да, может не быть недостаточным, но это не то, про что я думал. Можно считать что с ним всё ок.
сделать sanity check и посчитать число красивых чисел из одной цифры, я не шутил.
Вот серьёзно, нужно ответить на простой вопрос: сколько красивых чисел из одной цифры существует? Тут достаточно выписать этот (очень короткий) список на листке бумаги или посчитать их буквально на пальцах (у большинства людей пальцев хватит). А потом подставить эти входные данные в программу и мгновенно найти место, где появляется расхождение, и которое нужно поправить.
сделать sanity check и посчитать число красивых чисел из одной цифры, я не шутил. W>Вот серьёзно, нужно ответить на простой вопрос: сколько красивых чисел из одной цифры существует? Тут достаточно выписать этот (очень короткий) список на листке бумаги или посчитать их буквально на пальцах (у большинства людей пальцев хватит). А потом подставить эти входные данные в программу и мгновенно найти место, где появляется расхождение, и которое нужно поправить.
) относится — эту ошибку в логике они разделяют.
Не очень понимаю этот вопрос красивых чисел из одной цифры 0, из двух цифр 13. Какое это имеет отношение к логике решения?
A>Тестовое задание.
A>В данной задаче будут рассматриваться 13-ти значные числа в тринадцатиричной системе исчисления(цифры 0,1,2,3,4,5,6,7,8,9,A,B,C) с ведущими нулями.
A>Например, ABA98859978C0, 6789110551234, 0000007000000
A>Назовем число красивым, если сумма его первых шести цифр равна сумме шести последних цифр.
A>Пример:
A>Число 0055237050A00 — красивое, так как 0+0+5+5+2+3 = 0+5+0+A+0+0
A>Число 1234AB988BABA — некрасивое, так как 1+2+3+4+A+B != 8+8+B+A+B+A
A>Задача:
A>написать программу на С/С++ печатающую в стандартный вывод количество 13-ти значных красивых чисел с ведущими нулями в тринадцатиричной системе исчисления.
A>В качестве решения должен быть предоставлено:
A>1) ответ — количество таких чисел. Ответ должен быть представлен в десятичной системе исчисления.
A>2) исходный код программы.
У меня получилось 9203637295151
П.С.
Написал также программу которая в лоб считает, на малых числах вроде сходятся результаты.
Здравствуйте, Максим, Вы писали:
М>У меня получилось 9203637295151 М>П.С. М>Написал также программу которая в лоб считает, на малых числах вроде сходятся результаты.
Здравствуйте, Максим, Вы писали:
I>> count += cnt*cnt I>>Разве не так?
М>Выше Вы не учитываете, что между двумя частями может еще стоять одно из 13 чисел. М>
М>count += cnt*cnt*13
М>
М> должно давать правильный ответ (но остальную программу я не проверял)
Да точно, про центральное число я забыл. Достаточно мой ответ умножить на 13, почти правильно))
Re[5]: Задача на наследование с вызовом виртуальных функций
Здравствуйте, reversecode, Вы писали:
R>чуть по другому было в гцц старых около 3 версии R>там виртуальная таблица была толще, потому что у них pfn занимал 8 байт даже на 32битах, сейчас она стала такой же как и в msvc R>т.е 4 байта на 32 бита, 8 на 64 бита
Спрашивают, пойду ли я дальше.
На мой вопрос — к чему готовиться, очень мутно ответила hr.
Привожу пример, что другие дают список материалов для подготовки.
В ответ — "Всё, что знаю, 2 более тяжелые задачи. По моему опыту, если так... не сразу решили эту, то... обычно, кандидаты не решали те, которые на собеседование более тяжелые".
Допытал до примера. Покопалась по записям:
1) Задача на язык
2) Задача, как сказал один прошлый кандидат, которую можно и не решить длинной арифметикой. И следующая, которую можно решить длинной арифметикой
Т.е. либо 3 задачи. Либо даже про язык нету.
"Я, конечно, могу им отправить ваше резюме. И они позовут на интервью(очное). Просто, как правило, если эта задача была тяжела, то и те не получиться сделать. Подумайте, стоит ли тратить время".
Как думаете? Если почитать про эту арифметику, может попробовать?
Говорил, что раз математика, пускай, хотя бы, 3 рекомендованных учебника по матану выдадут.
Еще вопрос, если там и не было задачи на плюсы. И если 2 задачи чисто математические, то, может они там математические гики? Что мне там делать? Гуру олимпиадники?
Занимаются алго торговлей. Но я-то на прикладного инженера претендую, а не на кванта.
Это WunderFund? На мой взгляд, надо для себя решить в какой области Вы хотите развиваться. Если это алготрейдинг/hft/и подобное, то ничего не поделаешь, придется учиться решать задачи по комбинаторике, теории вероятностей и теории игр. Таковы правила игры, увы. Но может Вам оно и не надо, на них свет клином не сошелся, есть куча других интересных областей.
Здравствуйте, Максим, Вы писали:
A>>Спрашивают, пойду ли я дальше.
М>Это WunderFund? На мой взгляд, надо для себя решить в какой области Вы хотите развиваться. Если это алготрейдинг/hft/и подобное, то ничего не поделаешь, придется учиться решать задачи по комбинаторике, теории вероятностей и теории игр. Таковы правила игры, увы. Но может Вам оно и не надо, на них свет клином не сошелся, есть куча других интересных областей.
IT Prime.
Спасибо за обратную связь. Как смотрю по рынку — это наибольшие зп по С++. 300+ по идее можно.
Какие еще есть интересные области применения С++? И какие из них могут дать такие зп?
Еще момент с востребованностью.
Был свидетелем выхода на рынок middle QA manual. Он же junior QA java auto. Опыт в банке.
Пару часов открытого резюме — 30 откликов. За неделю — 10 собеседований, 4 оффера. Близко к 200к.
А здесь С++ + алгофонды.
6.5 фондов на всю Россию. Все они в Москве. У каждого могут быть или не быть адекватной вакансии.
Вот и вышел узкий специалист в узкой сфере.
A>Спасибо за обратную связь. Как смотрю по рынку — это наибольшие зп по С++. 300+ по идее можно. A>Какие еще есть интересные области применения С++? И какие из них могут дать такие зп?
Мне какжется, что по нынешним временам 300+, это не что-то такое грандиозное. В том же Яндексе можно столько заполучить (а с RSU и больше). Да практически во всех крупных конторах от Джетбрейнс до Касперского такие зарплаты есть. Выбирайте, что Вам интересно (спектр задач огромен, от теории компиляторов до систем хранения).
BFE>>>>>>>По стандарту (11.10.4/4) должен быть вызван метод A::printFromDestructor(), значит ответ: ~A, а не ~B, как ошибочно указано в комментарии. P>>>>>>Это ж вроде UB — удаление объекта по указателю на базу, а деструктор не виртуальный? BFE>>>>>Хмм. Действительно σ>>>>Какой опыт кодинга на цепепе? BFE>>>29 лет. А что? σ>>Не возраст, а опыт в C++. BFE>А это и есть опыт
Сорян, очень не хочется тебя расстраивать, но судя по https://rsdn.org/forum/cpp/8132925.1
σ>>>Я бы поинтересовался почему не S* s = new(storage) S("hello world"); вместо последних двух строк и в чём разница с дальнейшим использованием s (слева) в s->s.
BFE>>А она (разница) есть? storage не выровнен => s — unspecified. Разве нет? σ>Выравнивание… Ну да, может не быть недостаточным, но это не то, про что я думал. Можно считать что с ним всё ок.
σ, о чём вы подумали догадаться не сложно, вы лучше скажите, зачем объём storage равен удвоенному размеру S.
σ>>>>Я бы поинтересовался почему не S* s = new(storage) S("hello world"); вместо последних двух строк и в чём разница с дальнейшим использованием s (слева) в s->s.
BFE>>>А она (разница) есть? storage не выровнен => s — unspecified. Разве нет? σ>>Выравнивание… Ну да, может не быть недостаточным, но это не то, про что я думал. Можно считать что с ним всё ок. BFE>σ, о чём вы подумали догадаться не сложно, вы лучше скажите, зачем объём storage равен удвоенному размеру S.
Это вопрос к составителям теста.
Здравствуйте, reversecode, Вы писали:
R>и тогда на вопрос при собеседовании — что выведет тот код с не виртуальными деструкторами использующие виртуальные методы R>вы вы как практикующий программист с пруфами на все существующие компилеры скажете ?
>>from A >>the end
Я конечно могу быть неправым, но это происходит в силу логики переопределения указателя на таблицу виртуальных функций на т.текущего класса. любой имплементер бы сделал без вопросов если есть ненулевой указатель на т.в.ф (а где оно будет заменой указателя на this, или просто сменой указателя в рантайме в сях опять кто его знает, что это будет?), и безусловно сделал бы этот вызов до вызова деструктора. Потому оно и вероятно везде одинаковое. Но это — детали реализации и стандарт это не обсуждает. В силу чего в теории, ткскть стандарта может присутствовать только УБ. и вот это УБ меня лично вполне удовлетворяет. и знаете почему?
R>хотя вопрос будет наверняка провокационным и задающий будет ожидать ответа — уб
потому как любой может проверить, в силу общей костыльности и кустарности отрасли а идет ли вызов из виртуального деструктора или нет, просто потому, что до собственно указателя на твф добраться тяжело и нереально в заявленные сроки. и, соответственно, путь в графе к конечному вызову будет чем дальше, тем запутаннее. Потому, лучше глянуть, что в стандарте и ответить.
R>и я в +100500 раз бы повторил, лавер с++ != программист с++ R>этот точно так же как гражданин страны не обязан знать наизусть все законы той страны где он проживает,
R>иначе юристы бы померли от голода
От зря вы эту тему подняли. Юристы вообще не оперируют формальными языками, они условно говоря "чешут от балды" вроде бы некоторые мысли, которые еще проверять и проверять на однозначность, хотя вероятность нелогичного противоречивого бреда коррелирует с "положением дел", хотя кто и как это посчитает эту противоречивость, особенно, если она преднамеренная, да? Но вот опыта общения с юристами в своей области у меня был. так, что и непреднамеренной неоднозначности от них хватает).
Задача на многопоточность на парсинг файла.
На вход приходит файл под 1 Мб c сообщениями FIX формата
Прикрепляю фотку как это выглядит на облачном диске и как в реале, если открыть Notepad++.
В основном, сообщение это тег=значениеSOHтег=значениеSOH
SOH — это такой символ-разделитель.
В начале каждого сообщения 8=FIX.4.4.
Т.е. отдельное сообщение будет выглядеть:
8=FIX.4.4SOH9=75SOH35=0SOH49=MFIXTradeIDSOH56=MU0319300002SOH34=4949SOH52=20211215-20:10:16.250076549SOH10=244SOH
Нужно выдать на выходе подмножество сообщений:
1) Используя самописный пул поток распарсить файл
2) Давая возможность юзеру задать временной интервал. В сообщение есть метка времени в теге 52. Собственно, проверить, входит ли значение в интервал
3) Еще юзер может задать доп фильтрацию. Типа хочет сообщения еще у которых тег1=значение1 && тег2=значение1 ...
4) Пользоваться только С++ и std. Не пользоваться регулярками.
Пример вывода:
8=FIX.4.4|9=11|35=0|49=some1|12=mp2|52=20221016-10:12:15|10=2|
8=FIX.4.4|9=22|35=0|49=some2|12=mp2|52=20221016-10:13:16|10=2|
8=FIX.4.4|9=33|35=0|49=some3|12=mp2|52=20221016-10:14:46|10=2|
====================
Придумал такое решение:
а) Разделить исходный файл на куски == количеству ядер == количеству потоков
б) Каждому потоку отдать свой кусок и условие для фильтрации
в) Каждый поток:
-парсит свой кусок выделяя сообщения. Сохраняет очередное сообщение в map<сообщение, hash_map<тег, значение>>
-перебирает map проверяя условия — временная метка входит ли в интервал, теги имеют ли нужные значения
-добавляет отфильтрованные сообщения в результирующий вектор
-возвращает результирующий вектор
г) Основной поток main:
-дожидается результата=результирующих векторов от всех потоков.
-складывает все вектора в итоговый
-возвращает в stdout итоговый
A>Придумал такое решение: A>а) Разделить исходный файл на куски == количеству ядер == количеству потоков A>б) Каждому потоку отдать свой кусок и условие для фильтрации
Когда в дело вступает "диск", сложно обходиться теоретическими рассуждениями, все надо мерить на конкретной системе. Возможно быстрее будет работать подход, когда только один поток читает данные с диска и "накидывает" их пулу обработчиков.
П.С.
Владимир, как собеседования продвигаются? Понравились какие-нибудь конторы?
Здравствуйте, avovana, Вы писали:
A>Задача на многопоточность на парсинг файла. A>На вход приходит файл под 1 Мб c сообщениями FIX формата
A>Придумал такое решение: A>а) Разделить исходный файл на куски == количеству ядер == количеству потоков A>б) Каждому потоку отдать свой кусок и условие для фильтрации
Пара замечаний:
1. если файл всего 1 Мб, то быстрее его распарсить в один поток.
2. Как разделить файл на части, ведь одно сообщение может попасть в разные куски?
"For every complex problem, there is a solution that is simple, neat,
and wrong."
Re[2]: Многопоточно распарсить файл с fix сообщениями
Здравствуйте, AndrewJD, Вы писали:
AJD>Пара замечаний: AJD>1. если файл всего 1 Мб, то быстрее его распарсить в один поток. AJD>2. Как разделить файл на части, ведь одно сообщение может попасть в разные куски?
Ответил на своё же сообщение ссылкой на гитхаб.
1. Как оказалось, надо было уточнять. Похоже, входящий поток может быть и больше.
2. Верно подмечено. В реализации в моменте как-раз и добегал до окончания сообщения прежде чем кинуть весь кусок в поток. Чтобы очередному потоку пошёл кусок, который начинается с начала очередного сообщения.
Re[2]: Многопоточно распарсить файл с fix сообщениями
Здравствуйте, Максим, Вы писали:
М>Когда в дело вступает "диск", сложно обходиться теоретическими рассуждениями, все надо мерить на конкретной системе. Возможно быстрее будет работать подход, когда только один поток читает данные с диска и "накидывает" их пулу обработчиков.
Это интересно! Измерения не делал. Как бы Вы их сделали?
М>Владимир, как собеседования продвигаются? Понравились какие-нибудь конторы?
Спасибо, что поинтересовались. Устраиваюсь на новую работу.
Даже хотел статью написать. Точнее, цикл. Первая статья готова. Осталось картинку вставить и нажать "Отправить" из черновика хабра. Что-то не нажму всё никак)
Здравствуйте, avovana, Вы писали:
A>// написать функцию replace c 3-мя входными аргументами, возвращающую новую строку
input копируете и никак потом не используете. Тогда уж лучше по string_view передавать. substr и replace_to — тоже самое. Результирующая строка res гарантированно расширяется и неизбежны переаллокации памяти. Надо reserve добавить, как минимум.
Ну и куча мутабельных состояний, из-за чего алгоритм нечитабелен.
Здравствуйте, reversecode, Вы писали:
R>это наверное на джуниорские позиции ?
Синьор, принципал. R>обычно синьорам дают написать имплементацию strlen или strcpy
Такое никто не просил
Одну-две задачки в стиле leetcode, разного уровня сложности это да.
Вот приходите на интервью и вам говорят сделать:
"Реализацию тредпула с отложенным выполнением".
О чём в первую очередь подумаете когда услышите такую формулировку?
Какие есть мысли по реализации?
Какие есть хорошие примеры?
Я накопал в интернете несколько примеров:
======1========
Комбинация:
queue<function<void()>> jobs — в неё пишут функции для исполнения, из неё выгребают потоки пула чтобы исполнить.
vector<thread> — набор потоков для исполнения задач. В инициализации определяем сколько будет потоков.
mutex — один мьютекс на доступ записи в очередь очередной задачи, выбирания потоками на исполнение.
condition variable — сигнал от писателя, что есть данные в очереди. Потоки засыпают и ждут на ней пока не появятся данные.
// Использование:
thread_pool->QueueJob([] { /* ... */ });
class ThreadPool {
public:
void Start();
void QueueJob(const std::function<void()>& job);
void Stop();
void busy();
private:
void ThreadLoop();
bool should_terminate = false; // Tells threads to stop looking for jobs
std::mutex queue_mutex; // Prevents data races to the job queue
std::condition_variable mutex_condition; // Allows threads to wait on new jobs or termination
std::vector<std::thread> threads;
std::queue<std::function<void()>> jobs;
};
void ThreadPool::Start() {
const uint32_t num_threads = std::thread::hardware_concurrency(); // Max # of threads the system supports
threads.resize(num_threads);
for (uint32_t i = 0; i < num_threads; i++) {
threads.at(i) = std::thread(ThreadLoop);
}
}
void ThreadPool::ThreadLoop() {
while (true) {
std::function<void()> job;
{
std::unique_lock<std::mutex> lock(queue_mutex);
mutex_condition.wait(lock, [this] {
return !jobs.empty() || should_terminate;
});
if (should_terminate) {
return;
}
job = jobs.front();
jobs.pop();
}
job();
}
}
void ThreadPool::QueueJob(const std::function<void()>& job) {
{
std::unique_lock<std::mutex> lock(queue_mutex);
jobs.push(job);
}
mutex_condition.notify_one();
}
void ThreadPool::busy() {
bool poolbusy;
{
std::unique_lock<std::mutex> lock(queue_mutex);
poolbusy = jobs.empty();
}
return poolbusy;
}
void ThreadPool::Stop() {
{
std::unique_lock<std::mutex> lock(queue_mutex);
should_terminate = true;
}
mutex_condition.notify_all();
for (std::thread& active_thread : threads) {
active_thread.join();
}
threads.clear();
}
thread_pool->QueueJob([] { /* ... */ });
======2========
Реализация с помощью:
1) future + deferred. Как-то странно. Т.е. в пул как обычно кинули задачу. Внутри пул её обернули в future+deferred, положил в очередь. Поток проснулся, взял её. Выполнил get. Зачем эта связка — future + deferred? В этом же потоке происходит исполнение
2) Прокидывание аргументов — хорошая фича. Нет ограничений в сравнение с прошлым примером
Самый понятный и простой на данный момент пул.
#pragma once
#include <future>
#include <thread>
#include <condition_variable>
#include <atomic>
#include <queue>
#include <vector>
#include <tuple>
#include <functional>
#include <utility>
class ThreadPool {
using Task = std::future<void>;
public:
explicit ThreadPool(std::size_t threads_num);
~ThreadPool();
template <typename F, typename ... Args>
void addTask(F f, Args&& ... args) {
{
std::lock_guard<std::mutex> l(cv_m_);
if (quit_) {
throw std::runtime_error("adding task to stopped threadpool");
}
tasks_.emplace(std::async(std::launch::deferred, std::forward<F>(f), std::forward<Args>(args)...));
}
condition_.notify_one();
}
private:
std::mutex cv_m_;
std::condition_variable condition_;
std::atomic_bool quit_ = false;
std::queue<Task> tasks_;
std::vector<std::thread> workers_;
};
ThreadPool::ThreadPool(std::size_t threads_num)
{
for (std::size_t i = 0; i < threads_num; ++i) {
workers_.emplace_back(
[this](){
while (true) {
std::unique_lock<std::mutex> lk(this->cv_m_);
condition_.wait(lk, [this](){
return !this->tasks_.empty() || this->quit_;
});
if (this->quit_ && this->tasks_.empty()) {
return;
}
if (!this->tasks_.empty()) {
auto f = std::move(this->tasks_.front());
this->tasks_.pop();
lk.unlock();
f.get();
}
}
}
);
}
}
ThreadPool::~ThreadPool() {
quit_ = true;
condition_.notify_all();
for (auto& worker : workers_) {
worker.join();
}
}
Re[2]: Реализация тредпула с отложенным выполнением
Заинтересовался что-то, тем более правильный ответ есть.
Вот вариант на JS
// число цифр слева и справа от центральнойconst m = 6;
// общее количество цифр - оно же система счисленияconst n = m * 2 + 1;
// последняя цифра в системе счисления по основанию nconst lastNumber = n - 1;
// максимальная сумма m цифрconst maxSum = lastNumber * m;
// массив для подсчета количества вариантов разных значений суммы m цифрconst aSum = new Array(maxSum + 1).fill(0);
// максимальное число, которое можно представить m разрядами в системе счисления по основанию n
let maxNumber = 0;
for (let i = 0; i < m; ++i) {
maxNumber += n ** i * lastNumber;
}
// перебираем все варианты расположения цифр в m разрядах
// и подсчитываем в массиве aSum количество значений суммыfor (let i = 0; i <= maxNumber; ++i) {
const s = changeBaseNumber(i, n).reduce((partialSum, a) => partialSum + a, 0);
aSum[s]++;
}
// вычисляем общее количество "красивых" чиселconst result = aSum.reduce((partialSum, a) => partialSum + a * a * n, 0);
// сверяем с правильным результатом
console.log(result === 9203637295151);
/**
* Возвращает массив цифр для системы счисления по основанию osn для числе i
* @param {number} i
* @param {number} osn
* @returns
*/function changeBaseNumber(i, osn) {
const aOsn = [];
let i0 = i;
let j = 1;
while (true) {
const ost = i0 % osn;
i0 = (i0 - ost) / osn;
aOsn.push(ost);
if (i0 === 0) break;
j++;
}
return aOsn;
}
Жизнь не обязана доставлять удовольствие. Достаточно отсутствия страданий.
#include <iostream>
#include <vector>
using namespace std;
int _pow(int i, int j)
{
int result = 1;
for (int k = 0; k < j; ++k)
{
result *= i;
}
return result;
}
vector<int> changeBaseNumber(int i, int osn)
{
vector<int> aOsn;
int i0 = i;
int j = 1;
while (true)
{
int ost = i0 % osn;
i0 = (i0 - ost) / osn;
aOsn.push_back(ost);
if (i0 == 0) break;
j++;
}
return aOsn;
}
int main()
{
int m = 6;
int n = m * 2 + 1;
int lastNumber = n - 1;
int maxSum = lastNumber * m;
vector<int> aSum(maxSum + 1, 0);
int maxNumber = 0;
for (int i = 0; i < m; ++i)
{
maxNumber += _pow(n, i) * lastNumber;
}
for (int i = 0; i <= maxNumber; ++i)
{
int s = 0;
for (auto& v : changeBaseNumber(i, n))
{
s += v;
}
aSum[s]++;
}
long long result = 0;
for (auto& v : aSum)
{
result += (long long)v * v * n;
}
cout << result << endl;
cout << (result == 9203637295151 ? "True" : "False") << endl;
}
Жизнь не обязана доставлять удовольствие. Достаточно отсутствия страданий.
Re[2]: Реализация тредпула с отложенным выполнением
Здравствуйте, _NN_, Вы писали:
_NN>В нескольких компаниях спрашивали как написать планировщик. _NN>Ещё из вопросов как наиболее быстро фильтровать поступающие данные.
И как написать планировщик?
Какое конкретное задание предполагалось?
Подъехали вопросы общего плана с последнего weekend offer собеседования в топовую российскую компанию. Как бы вы ответили?
Можно кратко. Можно и расширенно. Почему бы и нет
Мне было немного не комфортно отвечать, т.к. отвечал кратко, но интервьюер отвечал как-то, что как-будто я не то сказал. Я начинал говорить больше. И боялся, что сам себя закапывал. Хотя говорил, вроде, нормально)
Не понимал, ответил ли я то что интервьюер хотел услышать/мог отметить у себя галочкой в тетрадке.
Короче, не часто бывает такое ощущение не понимания насколько попал, хотя говорил, вроде нормально.
Сами вопросы достаточно классные. Пожалуй, если можете ответить, думаю, можно спокойно пробоваться в текущие топ российские компании.
1. Что такое указатель?
2. Как он работает?
3. Из чего он состоит?
4. Что такое segfault? Объясните механику процесса.
5. Есть процесс с 1 Тб данных. Сделали форк. Насколько быстро отработает? Оцените количественно.
6. Что такое top load average?
7. Что лучше — мьютексы или атомики?
8. Что за засыпание потока на мьютексе?
9. Сложность поиска в отсортированном массиве?
10. Есть бинарное дерево. За сколько будет поиск?
11. Есть элементы со свойством "приоритет". Какую использовать структуру данных, чтобы быстро выполнять операции put, get. get выбирает элемент с макс. приоритетом и удаляет его.
12. Виртуальные таблицы. Что это? Как работают? Как их применяют? Где они хранятся? И кто и как их туда кладёт?
13. Как устроен weak_ptr?
14. Есть iterator на элемент в std::map. В std::map добавили новый элемент. Валиден ли итератор?
15. Есть iterator на элемент в std::vector. В std::vector добавили новый элемент. Валиден ли итератор?
16. Есть iterator на элемент в std::unordered_map. В std::unordered_map добавили новый элемент. Валиден ли итератор?
17. В чём отличие tcp и udp?
18. Что происходит при вызове write, send в tcp socket? Что означает выполнение этих функций?
Интервьюер до старта этих вопросов сказал, что есть опросник с вопросами на пол часа. Если нормально проходимся, то дадут задачку. Задачку после моих ответов дали. Значит ответил в целом норм)
Здравствуйте, avovana, Вы писали:
A>Здравствуйте, _NN_, Вы писали:
_NN>>В нескольких компаниях спрашивали как написать планировщик. _NN>>Ещё из вопросов как наиболее быстро фильтровать поступающие данные.
A>И как написать планировщик?
Есть много вариантов.
Вам идея нужна или код ?
Быстрый поиск в github выдает кучу результатов для просмотра.
Скажем, планировщик задач где каждая задача это поток, а в винде есть ограничение у WaitForMultipleObjects не позволяющее ожидать сигнлаов более чем от 64-х объектов.
Начиная с третьего года опыта ты просто научаешься не писать двусмысленные конструкции.
Поэтому я на 90% этих вопросов не знаю ответы. Знал до 2000-го года, а сейчас забыл.
Не нужно это на практике.
PS.
Я бы лучше именование переменных проэкзаменовал.
Как Вы назовёте такую-то сучность по-английски и по-русски?
PS2.
И пишете ли вы козлы документацию на свой код?
Здравствуйте, _NN_, Вы писали:
A>>И как написать планировщик? _NN>Есть много вариантов. _NN>Вам идея нужна или код ?
Посмотрел, спасибо!
А если словами — что просили сделать? То есть, в гитхабе там на все случаи жизни со всеми возможными обработками ошибок.
Интересно, что в рамках собеса было. Как формулировалась задача. Чётко, или нет? Насколько уточняли, что нужно сделать? И что реализовали за отведенное время? Какие идеи и как?
Всё это очень интересно