Подтвердить что ты не робот

Следует ли использовать статическую встроенную функцию?

Есть два значения использования ключевого слова inline (§ 7.1.3/4):

  • Он подсказывает компилятору, что подстановка тела функции в точке вызова предпочтительнее обычного механизма вызова функции.
  • Даже если встроенная подстановка опущена, следуют другие правила (особенно w.r.t Одно правило определения) для строки.

Обычно любой основной компилятор в случае необходимости заменяет тело функции в точке вызова, поэтому функция маркировки inline просто для #1 не нужна.

Далее w.r.t #2, Как я понимаю, когда вы объявляете функцию как функцию static inline,

Ключевое слово static в функции заставляет функцию inline иметь внутреннюю привязку (встроенные функции имеют внешнюю привязку). Каждый экземпляр такой функции рассматривается как отдельная функция (адрес каждой функции отличается) и каждый экземпляр этих функций имеет свои собственные копии статических локальных переменных и строковых литералов (встроенная функция имеет только одну копию)

Таким образом, такая функция действует как любая другая функция static, а ключевое слово inline больше не имеет значения, оно становится излишним.

Итак, практическая маркировка функции static и inline обе не имеет никакого смысла. Либо он должен быть static (не самый предпочтительный), либо inline (наиболее предпочтительно),
Итак, используется ли static и inline вместе в функции практически бесполезно?

4b9b3361

Ответ 1

Ваш анализ верен, но не обязательно означает бесполезность. Даже если большинство компиляторов делают автоматически встроенные функции (причина № 1), лучше всего объявить inline только для описания намерения.

Без учета взаимодействия с функциями inline, static следует использовать экономно. Модификатор static в области пространства имен ранее устарел в пользу неназванных пространств имен (С++ 03 §D.2). По какой-то непонятной причине, которую я не могу вспомнить, она была удалена из устаревания на С++ 11, но вам это редко нужно.

Итак, практическая маркировка функции static и inline не имеет никакого смысла. Либо он должен быть статическим (не самым предпочтительным), либо встроенным (наиболее предпочтительным),

Нет никакого предпочтения. static подразумевает, что разные функции с одной и той же сигнатурой могут существовать в разных файлах .cpp (единицы перевода). inline без static означает, что для разных единиц перевода используется ОК для определения той же функции с идентичными определениями.

Предпочтительно использовать неназванное пространство имен вместо static:

namespace {
    inline void better(); // give the function a unique name
}

static inline void worse(); // kludge the linker to allowing duplicates

Ответ 2

Статические и встроенные ортогональные (независимые). Static означает, что функция не должна быть видимой вне единицы перевода, inline - это намек на компилятор, который программист хотел бы включить эту функцию. Эти два не связаны.

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

Пример:

source1.cpp:

inline int Foo()
{
  return 1;
}

int Bar1()
{
  return Foo();
}

source2.cpp:

inline int Foo()
{
  return 2;
}

int Bar2()
{
  return Foo();
}

Без использования static в Foo (или без использования анонимного пространства имен, что является предпочтительным способом для большинства программистов на С++), этот пример нарушает ODR, а результаты undefined. Вы можете протестировать с помощью Visual Studio результат Bar1/Bar2, который будет зависеть от настроек компилятора. В конфигурации отладки оба Bar1 и Bar2 возвращают одинаковое значение (вставка не используется, одна реализация случайно выбрана компоновщиком), в конфигурации Release каждая из них вернет заданное значение.

Ответ 3

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

То есть, только с static inline вы действительно можете заменить использование макроса, inline сам по себе недостаточно.

Простой поиск в Google для "статического встроенного" покажет вам страницы документации для компилятора, которые говорят об этом. Думаю, этого должно быть достаточно, чтобы ответить на ваш вопрос и сказать: "Нет, это не бесполезно". Вот один пример сайта, в котором обсуждается использование inline и, в частности, static inline http://www.greenend.org.uk/rjk/tech/inline.html

Ответ 4

Если вы говорите о свободных функциях (область namespace), ваше предположение верно. static inline функции действительно не имеют большого значения. Таким образом, static inline - это просто функция static, которая автоматически удовлетворяет ODR и inline является избыточной для цели ODR.

Однако, когда мы говорим о методах члена (class scope), функция static inline имеет значение.
Когда вы объявите метод class как inline, его полное тело должно быть видимым для всех единиц перевода, которые включают в себя class.

Помните, что ключевое слово static имеет другое значение, когда оно используется для class.
Изменить. Как вы знаете, функция static внутри class не имеет внутренней связи, другими словами, класс не может иметь разные копии своего метода static в зависимости от перевода (.cpp). Но бесплатная функция static в namespace/global scope имеет разные копии на каждую единицу перевода.

например.

// file.h
static void foo () {}
struct A {
  static void foo () {}
};

// file1.cpp
#include"file.h"
void x1 ()
{
  foo();  // different function exclusive to file1.cpp
  A::foo();  // same function
}

// file2.cpp
#include"file.h"
void x2 ()
{
  foo();  // different function exclusive to file2.cpp
  A::foo();  // same function
}

Ответ 5

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