Чрезмерное встраивание, вероятно, должно решаться вызывающей стороной, настраивающей параметры компилятора, а не вызываемой стороной, пытающейся управлять ею с помощью очень грубых инструментов ключевого слова inline
и определений в заголовках. Например, у GCC есть -finline-limit
и друзья, поэтому вы можете использовать разные правила встраивания для разных единиц перевода. То, что для вас слишком сложно, может быть не слишком для меня, в зависимости от архитектуры, размера и скорости кэша команд, способа использования функции и т. Д. Не то, чтобы мне когда-либо приходилось выполнять эту настройку: на практике, когда она имеет стоило беспокоиться об этом, это стоило переписать, но это может быть совпадением. В любом случае, если я являюсь пользователем библиотеки, то при прочих равных я предпочел бы иметь возможность встроить (в зависимости от моего компилятора, и который я мог бы не использовать), чем не смог бы встроить.
Я думаю, что ужас от раздувания кода из библиотек, содержащих только заголовки, вызван опасениями, что компоновщик не сможет удалить избыточные копии кода. Таким образом, независимо от того, является ли функция на самом деле встроенной на сайтах вызовов или нет, проблема заключается в том, что вы получите вызываемую копию функции (или класса) для каждого объектного файла, который ее использует. Я не могу вспомнить, должны ли адреса, взятые для встроенных функций в различных единицах перевода в C ++, сравниваться одинаково, но даже если предположить, что это так, так что в связанном коде есть одна «каноническая» копия функции, это не обязательно означает, что компоновщик на самом деле удалит мертвые дубликаты функций. Если функция определена только в одном модуле перевода, вы можете быть уверены, что в статической библиотеке или исполняемом файле, который ее использует, будет только одна автономная копия.
Честно говоря, я не знаю, насколько обоснован этот страх. Все, над чем я работал, либо было настолько сильно ограничено в памяти, что мы использовали inline
только в качестве static inline
функций, настолько маленьких, что мы не ожидаем, что встроенная версия будет заметно больше, чем код, выполняющий вызов, и не возражайте против дубликатов, или иначе так слабо ограничены, что нас нигде не волнуют никакие дубликаты. Я еще никогда не занимал середину поиска и подсчета дубликатов на разных компиляторах. Иногда я слышал от других, что это проблема с кодом шаблона, поэтому я считаю, что в утверждениях есть доля правды.
Придумывая все это сейчас, я думаю, что если вы отправите библиотеку только с заголовками, пользователь всегда может связываться с ней, если им это не нравится. Напишите новый заголовок, который объявляет все функции, и новую единицу перевода, которая включает определения. Определенные в классах функции необходимо будет перенести во внешние определения, поэтому, если вы хотите поддерживать это использование, не требуя от пользователя разветвления кода, вы можете избежать этого и предоставить два заголовка:
// declare.h
inline int myfunc(int);
class myclass {
inline int mymemberfunc(int);
};
// define.h
#include "declare.h"
int myfunc(int a) { return a; }
int myclass::mymemberfunc(int a) { return myfunc(a); }
Звонящие, которые беспокоятся о раздувании кода, могут, вероятно, перехитрить свой компилятор, включив в свои файлы файл Declare.h, а затем написав:
// define.cpp
#include "define.h"
Им, вероятно, также необходимо избегать оптимизации всей программы, чтобы быть уверенным, что код не будет встроен, но тогда вы не можете быть уверены, что даже не встроенная функция не будет встроена оптимизацией всей программы.
Абоненты, которые не беспокоятся о раздувании кода, могут использовать define.h во всех своих файлах.