Пример простой, но при этом достаточно эффективной реализации многопоточного паттерна event loop. Да на хабре, да на английском. Используется std::function для задач, std::condition_variable.
https://habr.com/ru/articles/665730/
#cpp #multithreading #habr
https://habr.com/ru/articles/665730/
#cpp #multithreading #habr
Хабр
Idiomatic Event Loop in C++
Introduction Event Loop as a Tool TL;DR; Show Me The Code! The Basic Implementation The Power of std::function The Power of std::condition_variable The Power of Double Buffering A Couple of Remarks...
👍1
В std::list метод erase() возвращает итератор, следующий за удаленным элементом.
Почему? Ну во-первых итератор на удаленный элемент не валиден (он ведь удален), а во вторых это позволяет например организовать удаление из списка в цикле, вот так (1):
#cpp
Почему? Ну во-первых итератор на удаленный элемент не валиден (он ведь удален), а во вторых это позволяет например организовать удаление из списка в цикле, вот так (1):
std::list<int> lst = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
auto it = lst.begin();
while ( it != lst.end() ) {
if ( *it % 2 ) {
it = lst.erase(it); // (1) верно
//lst.erase(it); ++it; // (2) не верно
//lst.erase(it++); // (3) верно
} else {
++it;
}
}
Вариант (2) упадет (почему?), вариант (3) тоже рабочий, но возможно более сложный для понимания, чем (1) #cpp
std::list, обычно реализуемый как двусвязный список, имеет метод вставки элемента в начало push_front(). Понятно, что для двусвязного списка эта операция константна.
Разработчики же интерфейса std::vector предусмотрительно не стали реализовывать метод push_front(), так как добавление элемента в начало массива влечет необходимость переместить все элементы, а это уже O(n).
Однако вставить элемент в начало вектора все же можно, для этого следует воспользоваться методом insert():
Разработчики же интерфейса std::vector предусмотрительно не стали реализовывать метод push_front(), так как добавление элемента в начало массива влечет необходимость переместить все элементы, а это уже O(n).
Однако вставить элемент в начало вектора все же можно, для этого следует воспользоваться методом insert():
std::vector<int> v;#cpp
for (int i = 0; i < 5; ++i) {
v.insert(v.begin(), i);
}
// v = {4, 3, 2, 1, 0}
🔥1
Добавленный в C++11 std::forward_list реализует односвязный список, в отличие от двухсвязного std::list, и потому занимает меньше памяти. Однако за это приходится своеобразно платить. Допустим, мы находимся на элементе 3 и хотим его удалить. Для этого нужно изменить связь предыдущего элемента 2, но мы не можем к нему вернуться, так как связь идет в одну сторону (в двухсвязном в обе). Поэтому методы добавления и удаления элементов в forward_list изменяют элемент после указанного, так что мы можем обновить ссылку. Для этого в таком списке используется например не метод erase (которого вообще нет), а метод erase_after.
А что же делать с первым элементом, спросите вы, мои котятки? Как его удалить, если erase_after(begin) удалит элемент после первого, то есть второй? Для этого разработчики придумали интересный костыль, а именно метод before_begin(), который возвращает итератор на несуществующий элемент перед первым (аналогично тому, как во всех контейнерах end() указывает на несуществующий элемент после последнего). Вот так вот 😉.
#cpp
А что же делать с первым элементом, спросите вы, мои котятки? Как его удалить, если erase_after(begin) удалит элемент после первого, то есть второй? Для этого разработчики придумали интересный костыль, а именно метод before_begin(), который возвращает итератор на несуществующий элемент перед первым (аналогично тому, как во всех контейнерах end() указывает на несуществующий элемент после последнего). Вот так вот 😉.
#cpp
👍3
Найдите ошибку:
#cpp
std::vector<int> vec = {0,1,2,3,4,5,6,7,8,9};
auto mid = vec.cbegin() + 5;
auto findIt = std::find(vec.cbegin(), mid, 10);
if (findIt == vec.cend()) {
std::cout << "Not found";
} else {
std::cout << "Found";
}
Ошибочно выведется "Found", хотя 10 нет в векторе. Почему? Дело в том, что std::find не возвращает итератор end контейнера, если элемент не найден (указатель на end попросту негде взять). Вернет же функция второй параметр (last), если элемент не обнаружен. Правильно бы было сравнивать в if с mid (который не просматривается, к слову).#cpp
👍2
Интерактивная карта Ядра, можно местами потыкать код. Я офигела от количества макросов местами 😀
https://makelinux.github.io/kernel/map/
#linux
https://makelinux.github.io/kernel/map/
#linux
❤1🤔1
Сегодня 20 лет (!) известной статье Joel Spolsky (на минуточку сооснователя Stack Overflow) про "абсолютный минимум каждый разработчик абсолютно положительно должен знать о Юникоде и кодировках". Статья короткая, старая, но не потерявшая актуальности (перевод на русский). Читаем обязательно.
https://www.joelonsoftware.com/2003/10/08/the-absolute-minimum-every-software-developer-absolutely-positively-must-know-about-unicode-and-character-sets-no-excuses/
https://www.joelonsoftware.com/2003/10/08/the-absolute-minimum-every-software-developer-absolutely-positively-must-know-about-unicode-and-character-sets-no-excuses/
Часто бывает, что большой жирный класс реализует несколько интерфейсов и можно запутаться к какому именно принадлежит виртуальный метод. Было бы здорово, если имена методов можно было предварять именем интерфейса. Мне кажется, что это бы повысило читаемость. А может быть можно использовать для разрешения конфликта одинаковых имен от разных интерфейсов?
Или что-то такое уже есть?
Или что-то такое уже есть?
class Foo : public Interface, public Callback#cpp
{
public:
virtual bool Interface::start() override {}
virtual void Callback::onData() override {}
};
Вышел Qt 6.6. Изменения, конечно, забавные. Если улучшение модуля Qt TextToSpeech еще с точки зрения UI-фреймворка как-то можно понять (поддержка людей с ограниченными возможностями из коробки это хорошо), то вот добавление какой-то СУБД Mimer SQL (ни разу не слышала про такую), добавление класса для захвата содержимого отдельного окна QWindowCapture и тп вызывает ощущение дикого раздувания фреймворка. Лучше бы Qt Widgets полировали. (А вообще, конечно, кьют - ванлав 🫶).
https://www.opennet.ru/opennews/art.shtml?num=59907
#cpp #qt
https://www.opennet.ru/opennews/art.shtml?num=59907
#cpp #qt
www.opennet.ru
Релиз фреймворка Qt 6.6
Компания Qt Company опубликовала релиз фреймворка Qt 6.6, в котором продолжена работа по стабилизации и наращиванию функциональности ветки Qt 6. В Qt 6.6 обеспечена поддержка платформ Windows 10+, macOS 11+, Linux (Ubuntu 22.04, openSUSE 15.4, SUSE 15 SP4…
На собеседовании спросили, что делает эта функция:
В качестве подсказки предложили подставлять значения 1, 2, 3 , и тд.
Давайте попробуем:
[i bin(i) bin(i-1) bin(&) res]
1 0001 0000 0000 true
2 0010 0001 0000 true
3 0011 0010 0010 false
4 0100 0011 0000 true
5 0101 0100 0100 false
6 0110 0101 0100 false
7 0111 0110 0110 false
8 1000 0111 0000 true
Как видим, функция истинна если ее параметр это степень двойки (2^0=1, 2^1=2, 2^2=4). Это работает потому что степень двойки "перепрыгивает" на следующий разряд в двоичном представлении, а предыдущее число это все единицы, что при & дает 0.
#cpp
bool f(int i)
{
return i > 0 && (i & (i - 1)) == 0;
}
В качестве подсказки предложили подставлять значения 1, 2, 3 , и тд.
Давайте попробуем:
[i bin(i) bin(i-1) bin(&) res]
1 0001 0000 0000 true
2 0010 0001 0000 true
3 0011 0010 0010 false
4 0100 0011 0000 true
5 0101 0100 0100 false
6 0110 0101 0100 false
7 0111 0110 0110 false
8 1000 0111 0000 true
Как видим, функция истинна если ее параметр это степень двойки (2^0=1, 2^1=2, 2^2=4). Это работает потому что степень двойки "перепрыгивает" на следующий разряд в двоичном представлении, а предыдущее число это все единицы, что при & дает 0.
#cpp
👍3