Задать вопрос
  • Является ли одинаковой скорость 2-х фрагментов кода (доступ к элементу массива по индексу)?

    gbg
    @gbg Куратор тега C++
    Любые ответы на любые вопросы
    Из общих соображений - да, умножение нужно и там и там. Однако! Представленный код является шаблоном, следовательно, будет инлайнится по месту. Следовательно - нужно смотреть конкретный код, который вызывает этот метод - может оказаться так, что компилятор сможет выкинуть умножение совсем - например, если обращение происходит в цикле - можно ведь шагать сразу на размер инта.

    В любом случае, такой уровень экономии на спичках имеет реальную ценность только после того, как все остальные способы оптимизации программы уже выполнены, потому что это недалеко от реализации на ассемблере и интринсинках.
    Ответ написан
    1 комментарий
  • Является ли хорошей практикой ввод приватного ключа через терминал на старте приложения(сервера), а не через файл?

    saboteur_kiev
    @saboteur_kiev Куратор тега Информационная безопасность
    software engineer
    Нет.

    Если ключ физически будет на флешке, то в момент запуска все равно нужно его вставить в сервер и он будет на файловой системе. А если отключить флешку, а приложение нужно срочно перестартовать - у тебя это не получится сделать удаленно.

    Если у тебя есть опасения по поводу приватного ключа, сгенерирую ключ с passphrase, оно для этого и придумано
    Ответ написан
    3 комментария
  • Почему Clang (с -O3) не векторизует данный цикл?

    mayton2019
    @mayton2019
    Bigdata Engineer
    В первом варианте был массив четверок int или массив 128 битных элементов.
    Во втором случае - два независимых массивка 64х битных элементов которые в памяти
    расположены достаточно далеко и для них скорее всего не нашлось такой векторной
    команды которая-бы адресовалась к паре 64 + 64.
    Ответ написан
    9 комментариев
  • Какие компиляторы "принято" использовать в клиентских приложениях для разных платформ (Windows, MacOS etc)?

    Кажется, что всё-таки чаще Clang/LLVM, тк он под капотом умеет компилировать под MSVC ABI, если компилируешь под винду, и GNU ABI, когда компилируешь под Linux.
    Ответ написан
    Комментировать
  • Интеграция C++ в Electron'е?

    C++ умеет компилироваться в wasm, а wasm умеет работать с канвасом через webgl.

    Но, ИМХО, если идти в эту сторону, то использование какого-нибудь tauri+Rust выглядит разумнее, чем Electron + C++
    Ответ написан
    1 комментарий
  • Proof of work как защита от разного вида спама?

    У подхода минусов возможно и нет, потому что PoW изначально как защита от спама и задумывался, а вот с реализацией могут быть проблемы, например антивирусы могут ругаться, принимая за майнер, ОС видя 100% загрузку процесса может начать прижимать ресурсы для приложения, для пользователя 10-15 секунд это очень большое время, а для атакующего 10-15 секунд CPU может быть вполне приемлемое время, смотря какие прибыли он из этого извлекает.
    Ответ написан
    3 комментария
  • Можно ли объявить переменную-член класса с помощью метапрограммирования?

    @MarkusD Куратор тега C++
    все время мелю чепуху :)
    Соберем немного конкретики из комментариев.

    Отсюда:
    Только хотелось бы без специализации, чтобы код не дублировать

    Единственным дублированием кода тут будет только заголовок частичной специализации шаблона. В силах писателя определить общий между специализациями код и вынести его в родительский для всех специализаций класс.
    А с подобным дублированием справляется шаблон std::enable_if[?]. Часто его используют для выбора поведения шаблона исходя из черт аргумента шаблона.

    В твоем же случае можно успешно применять между реализацией с полем и реализацией без поля.
    Например, в виде такого упрощения определять общее поведение всего типа.

    Отсюда:
    соответственно во всех методах, где этот член используется можно будет проверку if constexpr (someCondition)

    Я подобные блоки кода называю замусореванием. Это как будто шел человек, захотел есть, пошел к палатке, купил еду, поел, а обертку и все остальное кинул прямо перед палаткой. Намусорил и ушел.
    Вот и писатель кода нередко в пылу решения задачи заходит в код, что-то дописывает, решает свои житейские проблемы и в результате код становится замусоренным. В коде больше не видно поведения, в коде появляются всякие сервисные штуки для этого кода. Код становится тяжело читать. А шаблонный код всегда и вдвойне тяжелее читать.

    За чистотой кода нужно следить. Подобные вещи, как вот такие блоки if constexpr, нужно убирать в функции. А где эти функции лучше расположить? Верно - прямо там, где для их работы определены данные. Поэтому на самом деле if constexpr не нужен. Нужно определить набор функций с поведением там где оно возможно. А где нет - определить заглушки чтобы клиентский, относительно вариативного поведения, код не нуждался в проверках и мог просто обращаться к вариативному поведению так, как будто оно не вариативно и есть всегда.
    Опять же, тут хорошо подходит пример с DebugName[?], в котором такие заглушки реализованы.
    Ответ написан
    1 комментарий
  • Можно ли объявить переменную-член класса с помощью метапрограммирования?

    @res2001
    Developer, ex-admin
    Условия можно проверять с помощью enable_if.
    Переменную, видимо, придется запихнуть во вложенную шаблонную структуру, где и использовать enable_if.
    Я сам не силен в метапрограммировании, но можете начать по этой ссылке копать, там и примеров много.
    Ответ написан
    Комментировать
  • Assignment operator VS Destructor + Placement new, где аргумент placement new - prvalue?

    @dolusMalus
    С++ programmer from gamedev
    Мне кажется, что данный вопрос стоит рассмотреть с точки зрения нескольких позиций:
    1. Безопасность относительно исключений. Какой уровень гарантий должен предоставлять данный метод?
    2. Производительность. Критично ли получить максимально эффективный код или на данном этапе этим можно пожертвовать?
    3. Оценить проектное решение в свете известных и проверенных практик, например, принципы SOLID


    Для начала определяемся используются ли вообще исключения в Вашем проекте и если нет, то можно переходить сразу к вопросу о производительности. В противном случае, рассмотрим каждый случай:
    int32_t index = sizeof(T) * head;
            (reinterpret_cast<T *>(&buffer[index]))->~T();
            new (&buffer[index]) T(std::forward<Args>(args)...);
            head = (head + 1) % maxSize;

    данный вариант не предоставляет даже базовых гарантий (basic exception guarantee), т.к. если конструктор сгенерирует исключение, то мы уже закончили время жизни объекта вызвав деструктор, но не изменятся size и head; а значит мы пришли в невалидное состояние.

    int32_t index = sizeof(T) * head;
            (reinterpret_cast<T *>(&buffer[index]))->~T();
            new (&buffer[index]) T(std::forward<Args>(args)...);
            head = (head + 1) % maxSize;

    Можем сделать развилку по noexcept для конструктора с помощью SFINAE или if constexpr и в случае, если конструктор является noexcept; то оставить данный код. В противном случае придется уже действовать в зависимости от необходимого уровня гарантий, однако решения будут достаточно громоздкие: в добавок к развилке надо будет ловить исключение, пробрасывать его дальше, при этом восстанавливать объект или уменьшать счетчики и т.п. Более того можно вообще не обеспечить сильную гарантию при определенных условиях. Как видите, это уже сильно осложнило решение.
    Теперь к другому варианту:
    // Assignment operator
    //        (*(reinterpret_cast<T *>(&buffer[sizeof(T) * head]))) = T(std::forward<Args>(args)...);

    Здесь ситуация относительно лучше, т.к. проблемы могут быть только на уровне оператора присваивания, что как минимум перекладывает часть ответственности в сторону автора типа T. Однако воспользовавшись решением от Евгений Шатунов можно относительно легко получить достаточно понятный и "чистый" код на уровне сильных гарантий. Также стоит посмотреть в сторону copy and swap идиомы, как близкой к данной проблеме.
    По итогу при необходимости строгих гарантий стоит отдать предпочтение варианту с временным объектом.

    С точки зрения производительности, если нет необходимости в максимальной оптимизации, то стоит отдать предпочтение более понятному коду. Данный момент уже прекрасно освещен в ответе Евгений Шатунов, поэтому не вижу смысла повторяться. Однако формально если отбросить предположения об оптимизациях, то вариант с реконструированием по месту (деструктор -> конструктор) оптимальней, т.к. гарантировано не требует выделения дополнительных ресурсов от временного объекта и только две операции + нет необходимости в относительно сложном анализе на перемешаемость/копируемость. В случае со swap, мы можем таки попасть на копирование в зависимости от перемещаемости типа T.

    И часто забываемый, но крайне важный пункт про проектирование. Здесь нарушен Single responsibility принцип, что возможно и породило этот вопрос. Т.е. у Вас метод по добавлению элемента может удалять/заменять элементы, что должно вызвать вопросы. Более того, вы решили за клиента вашего API (даже если это и Вы сами) как нужно обрабатывать исключительную ситуацию по переполнению. Потом например вы решите, что в одном месте стоит сложить старые элементы в отдельную очередь в другом залогировать или удалять не по одному, а сразу половину буффера. Все это потребует переписывания метода add, а зачем и почему? Попробуйте убрать эту часть кода заменив на выбрасывание исключения или вариант с возвращением успешности операции (менее грамотное решение, но это уже из области субъективной оценки) и посмотреть как увеличится прозрачность и простота написания клиентского кода для этого метода. Еще стоит посмотреть на сходное проектное решение в std::vector и его методе pop_back. Подумайте почему он не возвращает удаленный элемент?

    Итого, если важна производительность и не важна работа с исключениями; то разумно выбрать вариант с реконструированием; иначе обмен с временным объектом. Но не стоит забывать всегда про анализ проектного решения и правильную ли Вы проблему вообще решаете.
    Ответ написан
    2 комментария
  • Assignment operator VS Destructor + Placement new, где аргумент placement new - prvalue?

    @MarkusD Куратор тега C++
    все время мелю чепуху :)
    К современному коду предъявляется немало требований. В частности, код должен отвечать определенным критериям качества чтобы иметь шансы на добавление в основной репозиторий в качестве решения задачи.
    Среди таких критериев качества нередко бывают: соответствие общему стилю кода, соответствие общему стилю форматирования, наличие документации или самодокументируемость, а так же - элементарная понятность для читателя.

    Читатель современного кода не должен задаваться вопросами: что тут делает ядовитый газ, зачем швабры и почему вентилятор такой большой [?].
    Читателю все должно быть понятно практически сразу, у него должно возникать как можно меньше вопросов.

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

    *reinterpret_cast<T*>( &buffer[ sizeof( T ) * head ] ) = T{ std::forward<Args>( args )... };

    Да, тут присутствует Value Initialization и оператор перемещения. Однако, оптимизация этого кода сведет все к довольно короткому и как можно более быстрому коду. Поэтому не стоит беспокоиться об этом на текущем этапе. Лучше беспокоиться о понятности кода для читателя.
    Столь же понятным будет и такой код:
    auto T vicar{ std::forward<Args>( args )... };
    std::swap( *reinterpret_cast<T*>( &buffer[ sizeof( T ) * head ] ), vicar );

    Он не будет вызывать много вопросов, разве только вопрос относительно использования std::swap, но только от людей со слабой привычкой пользоваться STL.

    Однако, такой код может привести к ошибке трансляции в том случае, если T является неперемещаемым. В твоем ЦБ должны присутствовать проверки на перемещаемость, копируемость и возможность размена состояний.
    Если T можно копировать, но не перемещать, использовать стоит оператор копирования.
    И только если ни копировать, ни перемещать T нельзя, следует пользоваться деструктором и размещающим конструктором.

    Я бы рекомендовал все три действия оформить в виде перегрузок шаблона функции со SFINAE, чтобы для любого T включалась только одна конкретная перегрузка шаблона.
    Ответ написан
    6 комментариев
  • Почему в с++11 появилась 1 перегрузка push_back и метод emplace_back, ведь можно было использовать универсальную ссылку?

    kray74
    @kray74
    emplace_back не помещает переданный объект в вектор, а создаёт новый объект сразу внутри вектора. В качестве аргументов emplace_back принимает параметры конструктора создаваемого объекта.

    Перечитал еше раз вопрос и понял, что я не на то отвечаю.
    По поводу двух версий push_back Howard Hinnant (член комитета по стандартизации C++) ответил, что проще было добавить новую функцию, чем изменять существующую.
    Ответ написан
    Комментировать
  • Существует ли такой анализатор кода?

    Viktor_T2
    @Viktor_T2
    python developer
    Комментировать
  • Член класса/структуры типа uint8_t * или int8_t *, оптимизация?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Тут проблема не в том, что член класса char*, а в том, что запись идет в char*, и из-за strict aliasing правил - это может быть запись куда угодно, в том числе в &this. Кешировать пришлось бы любой член структуры, любого типа.

    Эту же проблему можно воспроизвести в меньшем масштабе, если у вас в цикле есть запись в int* и чтение какой-то другой не меняющейся int переменной. Особенно, когда переменная в куче и указатель пришел в параметре функции. Вот компилятор офигеет и будет на каждой итерации ее загружать в регистр заново. Опять же, потому что ну не может он понять, что вот этот вот указатель не указывает на вот эту вот переменную.

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

    @sergiodev
    class CircularBufferBase
    {
    public:
        static const int32_t MEMBER_TO_BE_ACCESSIBLE_OUTSIDE = 0;
    };
    
    template <typename T, int32_t maxSize>
    class CircularBuffer : public CircularBufferBase {
        ...
    }


    CircularBufferBase::MEMBER_TO_BE_ACCESSIBLE_OUTSIDE
    Ответ написан
    1 комментарий
  • Является ли хорошей практикой использование Stack Trace библотек в дебаг сборке?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Это нормальная практика. Например, ваш браузер скорее всего именно таким инструментом пользуется (если он на хромиуме основан).
    Ответ написан
    9 комментариев
  • Header-only. Страдает ли размер бинарника?

    @Mercury13
    Программист на «си с крестами» и не только
    Для шаблонов Си++ в линкеры пришлось добавлять специальное исключение — ведь расшаблоненные функции будут повторяться в каждом имеющемся объектном файле.

    Теста ради сделал такой проект

    // MAIN.CPP
    #include <iostream>
    
    #include "tmpl.h"
    
    void doFile1();
    
    int main()
    {
        const char* x = "main";
        outThing(x);
        doFile1();
        return 0;
    }
    
    // FILE1.CPP
    #include "tmpl.h"
    
    void doFile1()
    {
        const char* x = "doFile1";
        outThing(x);
    }
    
    
    // TMPL.H
    #pragma once
    
    #include <iostream>
    
    template <class T>
    void outThing(const T& x)
    {
        std::cout << "The thing is " << x << std::endl;
    }


    Для чего x — при расшаблонивании появилось outThing(char[5]&) и соответстсвенно char[8]&.
    А теперь дамп линкера
    Discarded input sections
    
     .text$_Z8outThingIPKcEvRKT_
                    0x0000000000000000       0x50 debug/main.o
    
    Linker script and memory map
    
    .text$_Z8outThingIPKcEvRKT_
                    0x0000000140002900       0x50 debug/file1.o
                    0x0000000140002900                void outThing<char const*>(char const* const&)
    
    Ну и ещё парочка структур для раскрутки стека и подстановки адресов…


    Так что даже при -O0 оно не будет ничего дублировать. Да и логикой понятно: что дублировать, что не дублировать — один хрен потребуется специальная логика, и разницы мало.
    Ответ написан
    1 комментарий
  • Какова уязвимость данного подхода?

    ky0
    @ky0
    Миллиардер, филантроп, патологический лгун
    Поздравляю, вы изобрели "your own PFS" :)

    В принципе, внутри нормально зашифрованного канала можно делать что угодно, хоть обменяться ключами и установить новое, на основе этих ключей, соединение - только зачем? Всякого рода IPSec-туннели и site-to-site впны для того и служат, чтобы можно было внутри них пускать нешифрованный трафик, если, например, протокол шифрования не умеет.
    Ответ написан
    3 комментария
  • IntelliJ IDEA(или любая IDE Jetbrains) - можно ли как-то скрыть assert'ы?

    azerphoenix
    @azerphoenix
    Java Software Engineer
    Ну в принципе любой код можно скрыть (code folding) в IDEA.

    Можно например, выделить код и нажать ctrl + ' . '

    Можно попробовать выделить код, затем нажать ctrl + alt + T (Code -> Surround with) и выбрать удобный для вас тег, а затем прописать название для fold и скрыть блок

    https://www.jetbrains.com/help/idea/code-folding-s...

    Плагинов, которые автоматически скрывали бы assert я не встречал, но в принципе можно и написать небольшой плагин
    Ответ написан
    2 комментария
  • Есть ли уже существующая структура данных для данной задачи?

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

    Постройте двумерный массив, который будет говорить, можно ли собрать данную сумму первыми k объектами.

    Используя его можно относительно быстро восстанавливать все множества с заданной суммой а заодно посмотреть, какие суммы возможно набрать.
    Ответ написан
    1 комментарий