• Член класса/структуры типа uint8_t * или int8_t *, оптимизация?

    Lite_stream
    @Lite_stream Автор вопроса
    res2001, в MSVC это слово в сигнатуре метода просто делает тип restrict у this
    61bb48c4dd1ab523613715.png

    Почему не влияет ? Как раз теперь, в someSelfAliasableMember точно не может быть this (по крайней мере так будет думать компилятор)
  • Член класса/структуры типа uint8_t * или int8_t *, оптимизация?

    Lite_stream
    @Lite_stream Автор вопроса
    res2001, хм, тогда либо википедия дезинформирует
    Ключевое слово __restrict для метода структуры или класса C++ обозначает, что указатель this имеет тип «T * __restrict const». Пример:
    ,
    либо я не понимаю, тогда зачем this делать константным
  • Член класса/структуры типа uint8_t * или int8_t *, оптимизация?

    Lite_stream
    @Lite_stream Автор вопроса
    res2001, на самом деле кое-где это и не такая уж микро оптимизация, например, в методе для разрешения коллизий, который сначала находят пары-кандидаты для разрешении коллизии, а затем разрешает их, а пар (пара - состоит из каких-то двух типов T *, например, T - это какой-нибудь Shape) этих может быть очень много, это довольно прилично скажет на скорости работы алгоритма

    я просто не понимаю, почему __restrict по умолчанию не применяется к сигнатуре метода, делая this - константным указателем, потому как редко в коде встретишь что-то вроде this = something
  • Член класса/структуры типа uint8_t * или int8_t *, оптимизация?

    Lite_stream
    @Lite_stream Автор вопроса
    res2001, а для случая, когда заалиасится может this и его член - uint8_t * (как в шапке моего вопроса), я так понимаю, лучшим решением будет просто пометить метод как __restrict ? __restrict для методов в C++

    На всякий случай для ясности:
    class Example
    {
    private:
        uint8_t * someSelfAliasableMember;
        int a;
        int b;
        int c;
    
    public:
        
        Example() : someSelfAliasableMember(new uint8_t[100]) {}
    
        void doSomething() __restrict
        {
            for (int32_t i = 0; i < 10; ++i)
            {
                someSelfAliasableMember[i] = i;
            }
        }
    };


    То есть, насколко я понимаю, в случае передаваемых в функцию аргументов указателей (если они одного типа) они могут ссылаться на один участок памяти, и тогда, если они таки не ссылаются на один участок, их можно пометить, как __restrict
    А в случае с членом класса, из-за того, что signed/unsigned char * может ссылаться на что угодно(не наруушая strict aliasing), включая this, как __restrict уже нужно пометить именно сам метод (Первый ответ к вопросу)
  • Член класса/структуры типа uint8_t * или int8_t *, оптимизация?

    Lite_stream
    @Lite_stream Автор вопроса
    res2001, хм, а если у меня, например, в объекте первое поле uint8_t * buffer, и я в методе сделаю что-то вроде &(this->buffer[0]), тогда и &(this->buffer[0]) и uint8_t * buffer на одну и ту жу область ссылаться будут, не приведёт ли это к UB? Или достаточно просто не пользоваться псевдонимом для buffer в виде &(this->buffer[0]) ? ну то есть, если начал писать buffer[i] = value, то в этом же месте не нужно писать что-то вроде this->buffer[i] = value (где i может быть = 0)

    или я этим просто обещаю компилятору, что именно сам this не буду менять, а не то что под ним лежит, то есть:
    this->buffer[0] = value - так можно
    а вот this = something нельзя

    просто тогда не понятно, почему все методы класса по умолчанию не __restrict, ведь мы обычно никогда ничего не записываем в сам this ( this = something )
  • Член класса/структуры типа uint8_t * или int8_t *, оптимизация?

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


    То есть если в классе/структуре есть член типа unsigned/signed char *, то из-за strict aliasing пришлось бы кэшировать любую переменную (например, перед обработкой её в цикле) ?

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

    Ну и второе правило, если метод принимает указатели на один и тот же тип и они точно не overlapp'ятся в памяти, то нужно добавлять __restrict (в зависимости от компилятора(лучше макросом)), если конечно метод очень часто вызывается

    static void InterpolateSnapshot_Hermite_WithExtrapolation( float t,
                                                               float step_size,
                                                               float extrapolation,
                                                               const __restrict CubeState * a,
                                                               const __restrict CubeState * b,
                                                               __restrict view::ObjectUpdate * output )

    Вот, например, нашёл в реальном проекте, только непонятно зачем __restrict у view::ObjectUpdate * output, он же тут только 1, значит ни с кем алиасится не может
  • Член класса/структуры типа uint8_t * или int8_t *, оптимизация?

    Lite_stream
    @Lite_stream Автор вопроса
    Если нет необходимости в подобной локальной переменной, то не нужно "кэшировать".
    На уровне ассемблера все обращения к памяти происходят через регистры, так что в любом случае адрес из указателя будет записан в регистр и этот регистр будет индексироваться.


    В версии без кэширования в локальную переменную появляется дополнительная инструкция перед каждым присваиванием
  • Член класса/структуры типа uint8_t * или int8_t *, оптимизация?

    Lite_stream
    @Lite_stream Автор вопроса
    Частично это можно решить кешированием, можно попробовать поменять типы кое где.


    А добавление в сигнатуру метода __restrict (void method () __restrict {}) не является эквивалентным кэшированию в локлаьную переменную ? за исключением того, что ничего кэшировать не придётся, так как компилятор уже будет знать, что переменная ни с чем в рамках данного метода не overlapp'ится" в памяти ?
  • Statements внутри списка инициализации конструктора?

    Lite_stream
    @Lite_stream Автор вопроса
    Евгений Шатунов,
    там, к сожалению, более сложная логика, чем просто вызовы методов, поэтому использовать цепочки вызовов не получится
  • Statements внутри списка инициализации конструктора?

    Lite_stream
    @Lite_stream Автор вопроса
    res2001,

    извиняюсь, забыл уточнить: createObj() - приватный статический метод *


    floppa322, Если это статический метод Example/ExtremelyHeavyObjectBuilder/ExtremelyHeavyObject, то можете так делать.
    В случае статического метода ExtremelyHeavyObjectBuilder/ExtremelyHeavyObject требуется указать класс, т.е. будет что-то вроде ExtremelyHeavyObjectBuilder::createObj().

    ну да, просто в данном случае, билдер нужно подготовить, вызвав некоторые его методы, т.е. получается больше одного выражения, поэтому придётся всё равно обёртку делать


    Так же createObj может быть и свободной функцией.

    естественно может, просто предпочитаю в ооп-стиле писать )
  • Statements внутри списка инициализации конструктора?

    Lite_stream
    @Lite_stream Автор вопроса
    res2001,

    То что вы предлагаете (объявление builder и прочее), можно вынести в вышестоящий код, который будет создавать экземпляр Example, и в конструктор Example передавать результат builder.build(), в списке инициализации просто передадите параметр конструктора Example в параметр конструктора obj.


    можно, но, как я написал выше, более чистым решением мне видется вызов приватного метода
    Example()
    :  obj(createObj()) 
    {}
  • Statements внутри списка инициализации конструктора?

    Lite_stream
    @Lite_stream Автор вопроса
    Евгений Шатунов,
    Спасибо, кажется, обычного вызова метода будет достаточно внутри инициализации члена класса


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

    statement, indirect - это как раз те англицизмы, переведя которые на русский одним словом, только ухудшит понимание, поэтому я бы не стал это делать


    По поводу стиля кода. Оформление, откровенно говоря, рваное. Это точно так же заставляет задумываться, вчитываться и искать. Думаю, поэтому у тебя пока еще нет ответов. Лично мне потребовалось 4 раза перечитать код чтобы увидеть в нем инициализатор. Первые три раза я видел просто неправильный синтаксис. В широкой практике инициализатор оформляется примерно схожим образом: блоком по строкам. Посмотри пример.

    ну естественно, там вообще ни о каком стиле речи не идёт, потому что то что написано после Example(): и до тела конструктора - вообще псевдо код, предположительный синтаксис, который бы подошёл. Наверное, нужно было это указать
  • Можно ли обратиться к статическому полю шаблона класса без инстанцирования шаблона?

    Lite_stream
    @Lite_stream Автор вопроса
    Евгений Шатунов, хорошо, учту насчёт формулировки вопроса и конфигов для классов )
  • Можно ли обратиться к статическому полю шаблона класса без инстанцирования шаблона?

    Lite_stream
    @Lite_stream Автор вопроса
    Евгений Шатунов, ну и даже с приватными статическими константами хотелоь бы, чтобы на каждый тип шаблона копии переменных не создавались, то есть тут уже речь не идёт о красоте синтаксиса
    Поэтому похоже для таких случаев нужно сделать файлик вроде SharedConstants.h
  • Можно ли обратиться к статическому полю шаблона класса без инстанцирования шаблона?

    Lite_stream
    @Lite_stream Автор вопроса
    Благодарю за ответ :)

    Правда, вариант с наследованием, к сожалению тоже выглядит не таким чистым решением :(
  • Можно ли обратиться к статическому полю шаблона класса без инстанцирования шаблона?

    Lite_stream
    @Lite_stream Автор вопроса
    Евгений Шатунов,

    floppa322 , шаблон класса - это, прежде всего, шаблон типа. Это еще не тип и работать с шаблоном как с типом невозможно. Шаблон всегда требуется инстанцировать, результатом инстанцирования шаблона типа всегда будет тип, у которого уже можно получить доступ к полям и функциям.

    добавляя "фиктивные" шаблонные параметры как-то слишком костыльно

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


    Это-то я понимаю, просто думал, что вдруг есть какой-то хитрый сахар, чтобы провернуть то, что описано в вопросе )

    Вообще, на практике не так часто требуется константа константа одного класса в другом, но тем не менее мне такие случаи встречались

    Например:
    1.Класс A использует regex и, чтобы написать тест на него и не ctrl + c / ctrl + v regex можно просто доступиться до публичного regex'а класса A в тесте
    2. Или ещё более экзотический пример (тут уже не абстрактный, а конкретный пример): World (класс, агрегирующий всю игровую логику) работает на частоте Hz1, а класс Connection(класс, который шлёп пакеты клиентам с некоторой частотой) работает на частоте Hz2, которая вычисляет на основе Hz1. Можно было бы вынести Hz1 в файл вроде SharedConstants, но в данном случае код будет чище, если Hz1 оставить в лкассе World, так как всё-таки Hz1 больше относится к World, чем к SharedConstants
  • Является ли хорошей практикой использование Stack Trace библотек в дебаг сборке?

    Lite_stream
    @Lite_stream Автор вопроса
    Евгений Шатунов,

    Извиняюсь за глупый вопрос, но откуда у пользователя возьмётся корректный стек вызовов?

    Вот эта самая Backward-cpp и ей подобные выдачу коллстека и сделают корректной. Современная инструментация отладки позволяет опознать фрагменты встроенного кода и правильно оформить коллстек для выдачи.


    Проверял с -02 дамп стек трейса, в частности, Backward-cpp не восстановил именно исходный, до оптимизаций вид стека вызовов, но может быть я не до конца изучил его api, хотя оно достаточно простое и прямолинейное

    И на производительности конкретно установка обработчиков тоже не сказывается.

    я почему поинтересовался, потому что, например, само наличие блоков try/catch, насколько мне известно, немного замедляет приложение (не в момент пробрасывания исключения, а вообще)
  • Является ли хорошей практикой использование Stack Trace библотек в дебаг сборке?

    Lite_stream
    @Lite_stream Автор вопроса
    Евгений Шатунов,

    а, ещё вопрос: на практике в релизных сборках устанавливают ли колбэки на системные исключения, вроде сегфолта, с последующим выводом стека вызовов ? понятно, что с -o2 он будет менее информативен, но тем не менее

    и не влияет же на производительность приложения само наличие колбэка на системное исключение, с телом, логирующим стек вызовов ?
  • Является ли хорошей практикой использование Stack Trace библотек в дебаг сборке?

    Lite_stream
    @Lite_stream Автор вопроса
    Евгений Шатунов, стало быть, если приложение чисто серверное, то бояться декомпиляции не стоит ?