Думаю, ти чогось тут пропустив.
статична функція?
Оголошення функції статичною зробить її "прихованою" в її модулі компіляції.
Ім'я, що має область простору імен (3.3.6), має внутрішній зв'язок, якщо це ім'я
- змінна, функція або шаблон функції, який явно оголошено статичним;
3,5 / 3 - C ++ 14 (n3797)
Коли ім’я має внутрішній зв’язок, на об’єкт, який воно позначає, може посилатися імена з інших областей застосування в тій самій одиниці перекладу.
3,5 / 2 - C ++ 14 (n3797)
Якщо ви оголосите цю статичну функцію в заголовку, тоді всі блоки компіляції, включаючи цей заголовок, матимуть власну копію функції.
Річ у тім, що якщо всередині цієї функції є статичні змінні, кожен блок компіляції, включаючи цей заголовок, також матиме свою власну особисту версію.
вбудована функція?
Оголошення його вбудованим робить його кандидатом на вкладання (сьогодні це не означає багато в C ++, оскільки компілятор буде вбудований чи ні, іноді ігноруючи той факт, що ключове слово inline присутнє або відсутнє):
Оголошення функції (8.3.5, 9.3, 11.3) із вбудованим специфікатором оголошує вбудовану функцію. Вбудований специфікатор вказує реалізації, що вбудована підміна тіла функції в точці виклику має бути кращою перед звичайним механізмом виклику функції. Для виконання цієї вбудованої заміни в точці виклику не потрібна реалізація; однак, навіть якщо ця вбудована заміна опущена, інші правила для вбудованих функцій, визначені у 7.1.2, все одно повинні дотримуватися.
7.1.2 / 2 - C ++ 14 (n3797)
У заголовку це має цікавий побічний ефект: вбудовану функцію можна визначити кілька разів в одному і тому ж модулі, і компонувальник просто об'єднає "їх" в один (якщо вони не були вбудовані з причини компілятора).
Для статичних змінних, оголошених всередині, стандарт конкретно говорить, що є одна, і лише одна з них:
Статична локальна змінна у вбудованій зовнішній функції завжди посилається на один і той же об'єкт.
7.1.2 / 4 - C ++ 98 / C ++ 14 (n3797)
(функції за замовчуванням є зовнішніми, тому, якщо ви спеціально не позначите свою функцію як статичну, це стосується цієї функції)
Це має перевагу "статичний" (тобто його можна визначити в заголовку) без вад (він існує щонайбільше один раз, якщо він не вбудований)
статична локальна змінна?
Статичні локальні змінні не мають зв’язку (їх не можна називати іменами поза їх сферою дії), але має статичну тривалість зберігання (тобто вона є глобальною, але її побудова та руйнування підпорядковуються певним правилам).
статичний + вбудований?
Потім змішування вбудованого та статичного призведе до наслідків, які ви описали (навіть якщо функція вбудована, статичної змінної всередині не буде, і ви закінчите стільки статичних змінних, скільки у вас є одиниць компіляції, включаючи визначення ваших статичних функцій ).
Відповідь на додаткове запитання автора
Оскільки я написав запитання, я спробував його за допомогою Visual Studio 2008. Я спробував увімкнути всі параметри, які змушують VS діяти відповідно до стандартів, але цілком можливо, що я їх пропустив. Ось результати:
Коли функція просто "вбудована", існує лише одна копія статичної змінної.
Коли функція "статична вбудована", копій стільки, скільки одиниць перекладу.
Насправді справжнє питання полягає в тому, чи все повинно йти так, чи це ідіосинкразія компілятора Microsoft C ++.
Тож, гадаю, у вас є щось подібне:
void doSomething()
{
static int value ;
}
Ви повинні усвідомити, що статична змінна всередині функції, простіше кажучи, глобальна змінна, прихована для всіх, крім області дії функції, що означає, що до неї може дійти лише функція, яку вона оголосила всередині.
Вбудовування функції нічого не змінить:
inline void doSomething()
{
static int value ;
}
Буде лише одна прихована глобальна змінна. Той факт, що компілятор спробує вбудувати код, не змінить той факт, що існує лише одна глобальна прихована змінна.
Тепер, якщо ваша функція оголошена статичною:
static void doSomething()
{
static int value ;
}
Тоді він є "приватним" для кожної одиниці компіляції, тобто кожен файл CPP, включаючи заголовок, де оголошена статична функція, матиме власну приватну копію функції, включаючи власну приватну копію глобальної прихованої змінної, таким чином стільки змінних, скільки є одиниці компіляції, включаючи заголовок.
Додавання "inline" до "static" функції зі змінною "static" всередині:
inline static void doSomething()
{
static int value ;
}
має такий самий результат, як не додавання цього вбудованого ключового слова, що стосується статичної змінної всередині.
Отже, поведінка VC ++ правильна, і ви помилково сприймаєте справжнє значення "вбудований" та "статичний".