Интересная научная статья фокусируется именно на потреблении энергии (CPU + RAM) в дополнении к памяти и времени работы. Авторы сравнивают 27 популярных языков программирования, замеряя потребленные Джоули при решении 10 задач. Замер потребления энергии производится с помощью утилиты Intel’s Running Average Power Limit.
В финальной таблице (см пост ниже) по всем задачам можно например заметить как Java потребляет в 5 раз больше рамы, чем Си. По потреблению энергии и по времени работы в первой тройке C, Rust и C++. Примечательно, что Rust почти не отличается от C, а вот C++ отстает на 30-50%. В статье приводятся результаты для трех задач: binary-trees (выделение, обход и удаление множества двоичных деревьев), fannkuch-redux (индексируемый доступ к крохотным последовательностям интов) и fasta (генерация и запись случайных последовательностей ДНК). В первых двух задачах лидируют C/C++, в третьей же - Rust, при этом C++ в ней довольно заметно отстает. С чем это связано не понятно, возможно на плюсах медленнее вывод в файл или генератор случайных чисел. Ставить под сомнение сводные результаты 10 задач на основе данных по 3 я не буду.
Интересно, что Python уверенно занимает предпоследнюю строчку и в 70 раз "хуже" Си. Спасай природу, переписывай свой питон код на Си 😁
Полный текст статьи: https://haslab.github.io/SAFER/scp21.pdf
#cpp #rust #performance
В финальной таблице (см пост ниже) по всем задачам можно например заметить как Java потребляет в 5 раз больше рамы, чем Си. По потреблению энергии и по времени работы в первой тройке C, Rust и C++. Примечательно, что Rust почти не отличается от C, а вот C++ отстает на 30-50%. В статье приводятся результаты для трех задач: binary-trees (выделение, обход и удаление множества двоичных деревьев), fannkuch-redux (индексируемый доступ к крохотным последовательностям интов) и fasta (генерация и запись случайных последовательностей ДНК). В первых двух задачах лидируют C/C++, в третьей же - Rust, при этом C++ в ней довольно заметно отстает. С чем это связано не понятно, возможно на плюсах медленнее вывод в файл или генератор случайных чисел. Ставить под сомнение сводные результаты 10 задач на основе данных по 3 я не буду.
Интересно, что Python уверенно занимает предпоследнюю строчку и в 70 раз "хуже" Си. Спасай природу, переписывай свой питон код на Си 😁
Полный текст статьи: https://haslab.github.io/SAFER/scp21.pdf
#cpp #rust #performance
🔥2
"did everybody expect that to happen?" спрашивает докладчик. Такого уж я точно не ожидала. Он сравнил ускорение (speedup на легенде) двух приложений: wait-free находит сумму через std::atomic, в то время как mutex находит ту же сумму, используя одноименную блокировку и обычные (неатомарные) переменные.
Внезапно оказалось, что wait-free масштабируется значительно хуже простого mutex.
Детали и более подробное устройство атомиков тут: https://www.youtube.com/watch?v=ZQFzMfHIxng
#cpp #multithreading
Внезапно оказалось, что wait-free масштабируется значительно хуже простого mutex.
Детали и более подробное устройство атомиков тут: https://www.youtube.com/watch?v=ZQFzMfHIxng
#cpp #multithreading
Пример простой, но при этом достаточно эффективной реализации многопоточного паттерна 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
Часто бывает, что большой жирный класс реализует несколько интерфейсов и можно запутаться к какому именно принадлежит виртуальный метод. Было бы здорово, если имена методов можно было предварять именем интерфейса. Мне кажется, что это бы повысило читаемость. А может быть можно использовать для разрешения конфликта одинаковых имен от разных интерфейсов?
Или что-то такое уже есть?
Или что-то такое уже есть?
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