Производительность
Как было предложено в предыдущих ответах, использование ключевого слова inline
может сделать код быстрее за счет встраивания вызовов функций, часто за счет увеличения числа исполняемых файлов. «Встроенные вызовы функций» просто означают замену вызова целевой функции фактическим кодом функции после заполнения аргументов соответствующим образом.
Однако современные компиляторы очень хороши для автоматического включения вызовов функций без какого-либо запроса от пользователя при установке на высокую оптимизацию. На самом деле, компиляторы, как правило, лучше при определении того, какие вызовы для inline для увеличения скорости, чем люди.
Объявление функций inline
явно для увеличения производительности (почти?) Всегда не нужно!
Кроме того, компиляторы могут и игнорируют запрос inline
, если он им подходит. Компиляторы будут делать это, если вызов функции невозможно встроить (т. Е. Использовать нетривиальную рекурсию или указатели на функции), но также и если функция просто слишком велика для значительного прироста производительности.
Одно правило определения
Однако объявление встроенной функции с помощью ключевого слова inline
имеет другие эффекты и может фактически необходимо для удовлетворения правила единого определения (ODR): это правило в Стандарт C ++ гласит, что данный символ может быть объявлен несколько раз, но может быть определен только один раз. Если редактор ссылок (= linker) встретит несколько идентичных определений символов, он выдаст ошибку.
Одним из решений этой проблемы является обеспечение того, чтобы модуль компиляции не экспортировал данный символ, предоставив ему внутреннюю связь, объявив его static
.
Однако часто лучше пометить функцию inline
. Это говорит компоновщику объединить все определения этой функции в единицах компиляции в одно определение с одним адресом и совместно используемыми статическими переменными функции.
В качестве примера рассмотрим следующую программу:
// header.hpp
#ifndef HEADER_HPP
#define HEADER_HPP
#include <cmath>
#include <numeric>
#include <vector>
using vec = std::vector<double>;
/*inline*/ double mean(vec const& sample) {
return std::accumulate(begin(sample), end(sample), 0.0) / sample.size();
}
#endif // !defined(HEADER_HPP)
// test.cpp
#include "header.hpp"
#include <iostream>
#include <iomanip>
void print_mean(vec const& sample) {
std::cout << "Sample with x̂ = " << mean(sample) << '\n';
}
// main.cpp
#include "header.hpp"
void print_mean(vec const&); // Forward declaration.
int main() {
vec x{4, 3, 5, 4, 5, 5, 6, 3, 8, 6, 8, 3, 1, 7};
print_mean(x);
}
Обратите внимание, что оба .cpp
файла содержат заголовочный файл и, следовательно, определение функции mean
. Несмотря на то, что файл сохраняется с включенной защитой от двойного включения, это приведет к двум определениям одной и той же функции, хотя и в разных единицах компиляции.
Теперь, если вы попытаетесь связать эти два модуля компиляции - например, с помощью следующей команды:
⟩⟩⟩ g++ -std=c++11 -pedantic main.cpp test.cpp
вы получите сообщение об ошибке: «дублирующий символ __Z4meanRKNSt3__16vectorIdNS_9allocatorIdEEEE» (которое является искаженным именем нашей функции mean
).
Если, однако, вы раскомментируете модификатор inline
перед определением функции, код компилируется и связывается правильно.
Шаблоны функций представляют собой особый случай: они всегда встроенные, независимо от того, были ли они объявлены таким образом. Это не означает, что компилятор встроит вызовы , но они не будут нарушать ODR. То же самое верно для функций-членов, которые определены внутри класса или структуры.