Question

I search some related questions (such as Benefits of inline functions in C++?), but I still have questions.

If inline function is just to "provide a simple mechanism for the compiler to apply more OPTIMIZATIONS."

  1. Then can I set every function as inline function?
  2. If I wrongfully set a function as inline function, what would happen concerning performance?
  3. Any threshold that tells me what size of function should not be inline function?
Was it helpful?

Solution

Use inline only to satisfy the One Definition Rule. Don't bother with inline for performance reasons.

If inline function is just to "provide a simple mechanism for the compiler to apply more OPTIMIZATIONS."

If we're talking about the inline keyword, then this is not what inline is about. Like, at all.

All inline does is ensure that a function doesn't violate the One Definition Rule. It might also provide a hint to the compiler that the compiler should blow the code out inline, which may or may not improve speed, but the compiler is entitled to ignore that hint. And in fact in modern compilers they will ignore this hint a great deal of the time.

One of the cases where the compiler is very likely to not blow the code out inline is with big functions. That doesn't mean the function shouldn't be declared inline, however -- it all depends on how the function is declared, defined and used. But, again, it has nothing to do with performance.

Don't try to outsmart the compiler when it comes to applying optimization techniques. It's far better at making your program fast than you are.


Let's see what the Standard has to say on all of this.

7.1.2 Function specifiers

2/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.

This tells us that inline is a request to the compiler to blow the code out inline, and that compilers are not required to perform that substitution. But this also tells us that regardless of the compiler performing this inline substitution, the "other rules" defined in 7.1.2 still apply.

There was a time, long ago, when the optimization techniques employed by C++ compilers were primitive relative to the compilers of today. Back in those days, it might have made sense to use inline as an optimization technique. But these days, compilers are much better at optimizing your code. The compiler applies techniques that, today, would make your code faster than inlining ever would, even if the function isn't actually inlined. (One possible example, RVO.)

So the end result of this is that while the original intent of 7.1.2/2 might have been to give the programmer a manual-optimization technique, modern compilers optimize so aggressively that this original intent is largely moot.

So all that's left for inline are those "other rules." So what are those other rules? (C++11 verbiage)

4/An inline function shall be defined in every translation unit in which it is odr-used and shall have exactly the same definition in every case (3.2). [ Note: A call to the inline function may be encountered before its definition appears in the translation unit. — end note ] If the definition of a function appears in a translation unit before its first declaration as inline, the program is ill-formed. If a function with external linkage is declared inline in one translation unit, it shall be declared inline in all translation units in which it appears; no diagnostic is required. An inline function with external linkage shall have the same address in all translation units. A static local variable in an extern inline function always refers to the same object. A string literal in the body of an extern inline function is the same object in different translation units. [ Note: A string literal appearing in a default argument is not in the body of an inline function merely because the expression is used in a function call from that inline function. — end note ] A type defined within the body of an extern inline function is the same type in every translation unit.

Let's take a look at an example. Suppose we have this class template:

File: foo.h

#ifndef FOO_H     
#define FOO_H     

#include <string>     
#include <sstream>     

class StringBuilder    
{    
public:    
    template <typename T> inline StringBuilder& operator<<(const T& t)    
    {    
        mStream << t;    
        return * this;    
    }    
    operator std::string () const;    
private:    
    std::stringstream mStream;    
};    

StringBuilder::operator std::string() const     
{     
    return mStream.str();    
}     

#endif     

If we #include this file in main.cpp and use the StringBuilder, everything's fine:

File: main.cpp

#include <iostream>
#include <string>

int main()
{
    double d = 3.14;
    unsigned a = 42; 

    std::string s = StringBuilder() 
        << "d=" << d << ", a=" << a;
    std::cout << s << "\n";
}

Output:

jdibling@hurricane:~/dev/hacks$ ./hacks 
d=3.14, a=42

But if we want to use the StringBuilder in a second translation unit, we're going to have a problem:

File: other.cpp

#include <iostream>
#include <string>

#include "foo.h"

void DoSomethingElse()
{
    unsigned long l = -12345;
    long l2 = 223344;

    std::string s = StringBuilder()
        << "l=" << l << ", l2=" << l2; 
    std::cout << s << "\n";
}

Compiler output:

ninja: Entering directory `.'
[1/3] Building CXX object CMakeFiles/hacks.dir/main.o
[2/3] Building CXX object CMakeFiles/hacks.dir/other.o
[3/3] Linking CXX executable hacks
FAILED: : && /usr/bin/g++   -Wall -std=c++11 -g   CMakeFiles/hacks.dir/main.o CMakeFiles/hacks.dir/other.o  -o hacks  -rdynamic -lboost_regex-mt && :
CMakeFiles/hacks.dir/other.o: In function `std::operator|(std::_Ios_Openmode, std::_Ios_Openmode)':
/home/jdibling/dev/hacks/foo.h:21: multiple definition of `StringBuilder::operator std::string() const'
CMakeFiles/hacks.dir/main.o:/home/jdibling/dev/hacks/foo.h:21: first defined here
collect2: error: ld returned 1 exit status
ninja: build stopped: subcommand failed.

StringBuilder::operator std::string() is defined twice; once in main.cpp and again in other.cpp -- which violated the One Definition Rule.

We can fix this by making the function inline:

class StringBuilder
{
public:
    // [...]
    inline operator std::string () const;
//  ^^^^^^
private:
    std::stringstream mStream;
};

Compiler output:

ninja: Entering directory `.'
[1/3] Building CXX object CMakeFiles/hacks.dir/main.o
[2/3] Building CXX object CMakeFiles/hacks.dir/other.o
[3/3] Linking CXX executable hacks

This works because now operator std::string is defined on both translation units with exactly the same definition. It has the same effect as defining the function directly in the declaraton:

class StringBuilder
{
public:
    operator std::string () const
    {
        return mStream.str();
    }
private:
    std::stringstream mStream;
};

OTHER TIPS

Just because you make a function inline it doesn't mean the compiler has to make it inline. An inline function is a hint to the compiler, not an order.

A compiler will use a set of metrics, such as optimization level, build type (debug or release), code size etc to determine if a function should be inlined.

The basic programming rule for inlining is the function should be of less then 10 lines; But there is much more on how compiler sees it and what factors you should consider .

https://en.cppreference.com/w/cpp/language/inline

Then can I set every function as inline function?

If you set a really big function as inline it's fully compiler call if it will consider it as an inlining or not same is true for other small functions. You should not worry about how the compiler optimizes the code. Istead the advantages there are some disadvantages or declaring big functions as inline or defining them in .h to consider for inlining . For every inline function compiler tries to fit it into the compiler cache , and if the function is too big and you force inlining then there will be cache miss.

If I wrongfully set a function as inline function, what would happen concerning performance?

It's compiler call if it wants to inline it or not you can force it but, you have __forceinline in windows to forcefully inline for that also there is no guarantee that functions will be inlined. You can't force the compiler to inline a particular function, even with the __forceinline keyword. When compiling with /clr, the compiler won't inline a function if there are security attributes applied to the function, but use it judiciously as it fully depend on the judgement of the programmer how you want approach it. https://learn.microsoft.com/en-us/cpp/cpp/inline-functions-cpp?view=vs-2019 Never force it , if you are not sure .

Any threshold that tells me what size of function should not be inline function?

A function larger then 10 lines a basic rule still there is much to consider. There is by default inlining happening and compiler optimizes as per the defined rules.

The basic rule you should follow for inlining is to define small function in .h inorder to consider them for inlining . Never put large definations in .h files as they can really become an overhead for compiler .

If we assume that a compiler will paste the inline code at the point where the function is called, you would have large chunks of duplicated code.

Functionally, you may observe a negligible performance improvement, but a large increase in the size of your executable.

The primary reason to have the compiler paste the code rather than call the function is when the code in the function is smaller than or close to the overhead costs in calling the function and returning from it. A rule of thumb is a function of a few statements should be marked as inline. As others have stated, the inline keyword is a hint to the compiler, not a request.

Its ultimately complier decision to make function inline or not so if you declare function as inline its just gives a hint to compiler to make this function inline .

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top