Блог пользователя Fefer_Ivan

Автор Fefer_Ivan, 13 лет назад, По-русски

Доброе утро/день/вечер, Codeforces.

Сегодня я, сдавая задачу 89D - Космические мины на С++, задумался о том, что у в моем коде много коротких функций, которые вызываются по много раз, и о том, что это может повлиять на производительность. Я всегда пишу относительно короткие функции с inline. inline-функция (или встроенная функция) на этапе компиляции заменяется в коде не на вызов функции, а прямо на тело, т.е. как макрос, только на уровень ниже. 
Но если написать inline int f(){ //some code}, это не гарантирует, что компилятор сделает функцию f() встроенной, это только как бы намекает компилятору, что стоило бы сделать эту функцию таковой, а он уже сам решает стоит это делать или нет. 
Поэтому я решил проконтролировать компилятор и посмотреть, действительно ли все функции типа inline double dist(const point& a, const point& b) { return sqrtl(sqr(a.X - b.X) + sqr(a.Y - b.Y)); } стали встроенными. В результате небольшого гугления я получил следующие решения:
  • На g++ есть опция -Winline, которая генерирует warning, если функция, перед которой написано ключевое слово inline, не была сделана встроенной
  • На Visual C++ есть аналогичный warning 4-го уровня. Также можно писать перед функциями __forceinline. Если компилятор не сделает встроенной функцию с __forceinline, то он сгенерирует warning 1-го уровня.
  • Проголосовать: нравится
  • +34
  • Проголосовать: не нравится

»
13 лет назад, # |
Rev. 4   Проголосовать: нравится 0 Проголосовать: не нравится

Если я скомпилирую с -winline, мне компилятор скажет, что он не сделал функцию встроенной. Что мне это даст? То есть могу ли я как-то именить код, чтобы финкция стала встроенной? Если это возможно,  пожалуйста, расскажите, что конкретно надо изменить.

  • »
    »
    13 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится
    Вообще компиляторы для определения стоит встраивать функцию или нет использую неочевидный механизм, который как-то оценивает выгоду от встраивания, так что конкретный ответ дать сложно.
    Однако надо в общем случае надо просто сократить код, чтобы функция разворачивалась в меньшее число ассемблерных команд. Чем меньше функция, тем более выгодно её встраивать.
»
13 лет назад, # |
  Проголосовать: нравится -21 Проголосовать: не нравится
Думаю что современные компиляторы просто игнорируют твои inline, забудь про них и не пиши, код нормальный сгенерится. Если заходят решения на яве, то твое на C++ точно пройдет. Поэтому ИМХО, в отношении спортивного программирования, нужно просто забыть это слово, только трата времени на его набор и определение того где писать, а где не писать.
  • »
    »
    13 лет назад, # ^ |
      Проголосовать: нравится +20 Проголосовать: не нравится
    Зря. Такое бывает полезно когда что-то жестко впихиваешь. Еще пару раз видел, что вызовы функции size вектора занимают 35% времени работы программы. Кто там что говорил про адекватные компиляторы?
    • »
      »
      »
      13 лет назад, # ^ |
      Rev. 3   Проголосовать: нравится 0 Проголосовать: не нравится

      Интерестно. Это какой компилятор, какой вообще код? Потому что я использую макрос

      #define L(s) (int)((s).size())
      Раньше использовал
      #define L(s) (int)((s).end() - (s).begin())
      но после теста - сравнения вышло, что времени они в общем едят одинаково, так что теперь использую вариант, который выше.
      • »
        »
        »
        »
        13 лет назад, # ^ |
          Проголосовать: нравится 0 Проголосовать: не нравится
        G++. Разных версий. Я думаю что тут разницы особой нет, потому что второе и есть первое внутри. Хотя надо потестить. Разница ощущается на где-то на x * 106 вызовах. Если их просто сделать, то я думаю оптимизатор с этим справится, так что надо делать в каких-то нетривиальных ситуациях.
»
13 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится
Когда-то давно смотрел, как влияют inline, const и амперсанд на генерируемый код для подобной dist() функции. Оказалось, что никак: оптимизатор при любой комбинации модификаторов выдает один и тот же код с нулевым размером стекфрейма и делает инлайн, а если в аргументах есть константы, то еще и прекальк.
»
13 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится
Компилятор умнее чем ты думаешь. Большинство локальных функций в cpp-файлах всегда встраиваются (в современных компиляторах). Единственный повод этого не делать -- это рекурсия и слишком большой объем получаемого кода, но компилятор умеет хорошо это проверят /предсказывать.

Другой вопрос -- это написание библиотек, так уже важно inline метод или нет.