Редактировать 1: Добавлен код встраивания LLVM (другими словами "clang")
Изменить 2: добавить пояснение, как «разрешить» это.
Фактически правильный
Пункт 1, конечно, не требует пояснений.
Пункт 2 - ерунда - все современные компиляторы (по крайней мере, MS, GCC и Clang [aka XCode]) полностью игнорируют inline
ключевые слова и принимают решение исключительно на основе критериев частоты / размера (определение «коэффициента раздувания кода» на основе размера * количества раз, поэтому небольшие функции или функции, вызываемые только несколько раз, с большей вероятностью будут встроены - конечно, геттер будет идеальным выбором для всегда встраивания компилятором, поскольку это будет всего две или три инструкции и, скорее всего, короче, чем загрузка this
, затем вызывая функцию получения.
Ключевое слово inline
вообще не имеет никакого значения [и стандарт C ++ утверждает, что определение внутри класса в любом случае inline
].
Пункт 3 - еще один вероятный сценарий, но я бы подумал, что тот факт, что он неявно встроен в его определение, должен дать тот же результат. Некоторое время назад было обсуждение ключевого слова inline
и его значения в списке рассылки Clang, и был сделан вывод, что «компилятор обычно знает лучше».
Также обычно совершенно бесполезно использовать inline
вместе с виртуальными функциями, поскольку они почти всегда будут вызываться через запись vtable и не могут быть встроены.
Изменить 1:
Код взят из LLVM "InlineCost.cpp":
InlineCost InlineCostAnalysis::getInlineCost(CallSite CS, Function *Callee,
int Threshold) {
// Cannot inline indirect calls.
if (!Callee)
return llvm::InlineCost::getNever();
// Calls to functions with always-inline attributes should be inlined
// whenever possible.
if (CS.hasFnAttr(Attribute::AlwaysInline)) {
if (isInlineViable(*Callee))
return llvm::InlineCost::getAlways();
return llvm::InlineCost::getNever();
}
// Never inline functions with conflicting attributes (unless callee has
// always-inline attribute).
if (!functionsHaveCompatibleAttributes(CS.getCaller(), Callee,
TTIWP->getTTI(*Callee)))
return llvm::InlineCost::getNever();
// Don't inline this call if the caller has the optnone attribute.
if (CS.getCaller()->hasFnAttribute(Attribute::OptimizeNone))
return llvm::InlineCost::getNever();
// Don't inline functions which can be redefined at link-time to mean
// something else. Don't inline functions marked noinline or call sites
// marked noinline.
if (Callee->mayBeOverridden() ||
Callee->hasFnAttribute(Attribute::NoInline) || CS.isNoInline())
return llvm::InlineCost::getNever();
DEBUG(llvm::dbgs() << " Analyzing call of " << Callee->getName()
<< "...\n");
CallAnalyzer CA(TTIWP->getTTI(*Callee), ACT, *Callee, Threshold, CS);
bool ShouldInline = CA.analyzeCall(CS);
DEBUG(CA.dump());
// Check if there was a reason to force inlining or no inlining.
if (!ShouldInline && CA.getCost() < CA.getThreshold())
return InlineCost::getNever();
if (ShouldInline && CA.getCost() >= CA.getThreshold())
return InlineCost::getAlways();
return llvm::InlineCost::get(CA.getCost(), CA.getThreshold());
}
Как можно видеть (если немного покопаться в остальной части кода), есть только проверки для встроенных параметров «всегда» и «никогда». Нет для самого встроенного ключевого слова.
[Обратите внимание, что это встроенный код для clang и clang ++ - clang сам по себе не делает ничего особенно умного при генерации кода, это «просто» (расстроивший сотни программистов, потративших сотни лет на этот проект!) Синтаксический анализатор для C и C ++, который переводится в LLVM IR, все полезные и умные вещи выполняются на уровне LLVM - это действительно хороший способ предоставить "многоязычный" каркас компилятора. Я написал компилятор Pascal, и, несмотря на то, что я новичок в работе с компилятором, мой компилятор (который использует LLVM для генерации реального машинного кода) лучше в тестах (сгенерированного кода), чем Free Pascal - все благодаря LLVM, почти нет это моя работа - за исключением некоторого кода для встраивания нескольких часто называемых функций в один конкретный тест]
У меня нет доступа к источникам для компилятора MS (ох!), И мне не нужно загружать gcc только для того, чтобы проверить это. По опыту я знаю, что все три будут встраивать функции без ключевого слова inline, а gcc будет агрессивно встраивать функции, которые, как он может определить, имеют только одного вызывающего (например, большие static
вспомогательные функции)
Изменить 2:
Правильный способ решить эту проблему - иметь стандарт кодирования, который четко говорит, когда и где inline
[и функции, определенные внутри класса] должны использоваться, а когда этого делать не следует. Если в настоящее время ни одна из других небольших функций-получателей в других классах не имеет inline
, то было бы странно и бросалось в глаза, что эта функция имеет. Если все, кроме некоторых, имеют inline
, вероятно, это тоже следует исправить.
Еще один анекдот: мне лично нравится писать if-утверждения в виде
if (some stuff goes here)
(пробел между if и круглыми скобками, но не вокруг предмета внутри), но действующий стандарт кодирования гласит:
if( some stuff goes here )
(без пробела между if и скобками, но вокруг предмета внутри)
Я случайно получил что-то вроде этого:
if ( some stuff goes here )
в коде, который был рассмотрен. Я исправил эту строку, но решил ТАКЖЕ исправить 175 других if-операторов с пробелом после if
- всего в этом файле было менее 350 if-операторов, поэтому БОЛЕЕ половины из них были неправильными ...
person
Mats Petersson
schedule
11.11.2015
inline
в C ++ - предотвратить нарушения ODR в результате определения функций в файле заголовка. (в то время как в C он имеет ровно ноль полезных целей. Я знаю, что вы не спрашивали о C, но я подумал упомянуть этот факт в качестве пояснения.) - person The Paramagnetic Croissant   schedule 11.11.2015i
иj
для индексов массива. - person Craig Estey   schedule 11.11.2015__attribute__((always_inline))
, потому чтоinline
не гарантирует встраивания. А еще лучше, ему, вероятно, следует оставить решение компилятору; возможно, после включения оптимизации всего модуля (с использованием-flto
). - person The Paramagnetic Croissant   schedule 11.11.2015inline
не было бы решением, и ваше предложение относительно этих атрибутов было бы применимо. - person The Paramagnetic Croissant   schedule 11.11.2015