I have a function that is declared and defined in a header file. This is a problem all by itself. When that function is not inlined, every translation unit that uses that header gets a copy of the function, and when they are linked together there are duplicated. I "fixed" that by making the function inline, but I'm afraid that this is a fragile solution because as far as I know, the compiler doesn't guarantee inlining, even when you specify the "inline" keyword. If this is not true, please correct me.
Anyways, the real question is, what happens to static variables inside this function? How many copies do I end up with?
The inline variable is allowed to be defined in multiple translation units. It also follows the one definition rule. If this is defined more than one time, the compiler merges them all into a single object in final program.
An inline function is one for which the compiler copies the code from the function definition directly into the code of the calling function rather than creating a separate set of instructions in memory. This eliminates call-linkage overhead and can expose significant optimization opportunities.
If you need to make sure that function is inlined and OK to go with proprietary extension in MS VC++, check out the __forceinline declarator. The compiler will either inline the function or, if it falls into the list of documented special cases, you will get a warning - so you will know the inlining status.
Inline function may increase efficiency if it is small. 2) If a function contains static variables. 3) If a function is recursive. 4) If a function return type is other than void, and the return statement doesn't exist in function body.
I guess you're missing something, here.
Declaring a function static will make it "hidden" in its compilation unit.
A name having namespace scope (3.3.6) has internal linkage if it is the name of
— a variable, function or function template that is explicitly declared static;
3.5/3 - C++14 (n3797)
When a name has internal linkage , the entity it denotes can be referred to by names from other scopes in the same translation unit.
3.5/2 - C++14 (n3797)
If you declare this static function in a header, then all the compilation units including this header will have their own copy of the function.
The thing is, if there are static variables inside that function, each compilation unit including this header will also have their own, personal version.
Declaring it inline makes it a candidate for inlining (it does not mean a lot nowadays in C++, as the compiler will inline or not, sometimes ignoring the fact the keyword inline is present or absent):
A function declaration (8.3.5, 9.3, 11.3) with an inline specifier declares an inline function. The inline specifier indicates to the implementation that inline substitution of the function body at the point of call is to be preferred to the usual function call mechanism. An implementation is not required to perform this inline substitution at the point of call; however, even if this inline substitution is omitted, the other rules for inline functions defined by 7.1.2 shall still be respected.
7.1.2/2 - C++14 (n3797)
In a header, its has an interesting side effect: The inlined function can be defined multiple times in the same module, and the linker will simply join "them" into one (if they were not inlined for compiler's reason).
For static variables declared inside, the standard specifically says there one, and only one of them:
A static local variable in an extern inline function always refers to the same object.
7.1.2/4 - C++98/C++14 (n3797)
(functions are by default extern, so, unless you specifically mark your function as static, this applies to that function)
This has the advantage of "static" (i.e. it can be defined in a header) without its flaws (it exists at most once if it is not inlined)
Static local variables have no linkage (they can't be referred to by name outside their scope), but has static storage duration (i.e. it is global, but its construction and destruction obey to specific rules).
Mixing inline and static will then have the consequences you described (even if the function is inlined, the static variable inside won't be, and you'll end with as much static variables as you have compilation units including the definition of your static functions).
Since I wrote the question I tried it out with Visual Studio 2008. I tried to turn on all the options that make VS act in compliance with standards, but it's possible that I missed some. These are the results:
When the function is merely "inline", there is only one copy of the static variable.
When the function is "static inline", there are as many copies as there are translation units.
The real question is now whether things are supposed to be this way, or if this is an idiosyncrasy of the Microsoft C++ compiler.
So I suppose you have something like that:
void doSomething() { static int value ; }
You must realise that the static variable inside the function, simply put, a global variable hidden to all but the function's scope, meaning that only the function it is declared inside can reach it.
Inlining the function won't change anything:
inline void doSomething() { static int value ; }
There will be only one hidden global variable. The fact the compiler will try to inline the code won't change the fact there is only one global hidden variable.
Now, if your function is declared static:
static void doSomething() { static int value ; }
Then it is "private" for each compilation unit, meaning that every CPP file including the header where the static function is declared will have its own private copy of the function, including its own private copy of global hidden variable, thus as much variables as there are compilation units including the header.
Adding "inline" to a "static" function with a "static" variable inside:
inline static void doSomething() { static int value ; }
has the same result than not adding this "inline" keyword, as far as the static variable inside is concerned.
So the behaviour of VC++ is correct, and you are mistaking the real meaning of "inline" and "static".
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With