Inline functions in C++

2019-01-19 10:24发布

问题:

If we define a member function inside the class definition itself, is it necessarily treated inline or is it just a request to the compiler which it can ignore.

回答1:

Yes, functions that are defined inside a class body are implicitly inline.

(As with other functions declared inline it doesn't mean that the complier has to perform inline expansion in places where the function is called, it just enables the permitted relaxations of the "one definition rule", combined with the requirement that a definition must be included in all translation units where the function is used.)



回答2:

As stated by others, a method defined within a class is automatically requested inline. It's useful to understand why.

Suppose it weren't. You'd have to generate code for such a function, and everywhere it is called, a jump to subroutine instruction would have to reference the location, via the linker.

class A {
public:
  void f() { ... your code ... }
};

Every time this code is seen, if it's not inline, the compiler can only assume it must be generated, so it would generate a symbol. Suppose it was like this:

A__f_v:

If that symbol were global, then if you happened to include this class code multiple times in different modules, you would have a multiply defined symbol error at link time. So it can't be global. Instead, it's file local.

Imagine you include the above header file in a number of modules. In each one, it's going to generate a local copy of that code. Which is better than not compiling at all, but you're getting multiple copies of the code when you really need only one.

This leads the the following conclusion: if your compiler is not going to inline a function, you are significantly better off declaring it somewhere once, and not requesting it to be inlined.

Unfortunately, what is and is not inline is not portable. It's defined by the compiler writer. A good rule of thumb is to always make every one liner, particularly all functions which themselves just call a function, inline, as you remove overhead. Anything below three lines of linear code is almost certainly ok. But if you have a loop in the code, the question is whether the compiler will allow it inline, and more to the point, how much benefit you would see even if it did what you want.

consider this inline code:

inline int add(int a, int b) { return a + b; }

It's not only almost as small as the prototype would be in source code, but the assembly language generated by the inline code is smaller than the call to a routine would be. So this code is smaller, and faster.

And, if you happen to be passing in constants:

int c= add(5,4);

It's resolved at compile time and there is no code.

In gcc, I recently noticed that even if I don't inline code, if it's local to a file, they will sneakily inline it anyway. It's only if I declare the function in a separate source module that they do not optimize away the call.

On the other end of the spectrum, suppose you request inline on a 1000 line piece of code. Even if your compiler is silly enough to go along with it, the only thing you save is the call itself, and the cost is that every time you call it, the compiler must paste all that code in. If you call that code n times, your code grows by the size of the routine * n. So anything bigger than 10 lines is pretty much not worth inlining, except for the special case where it is only called a very small number of times. An example of that might be in a private method called by only 2 others.

If you request to inline a method containing a loop, it only makes sense if it often executes a small number of times. But consider a loop which iterates one million times. Even if the code is inlined, the percentage of time spent in the call is tiny. So if you have methods with loops in it, which tend to be bigger anyway, those are worth removing from the header file because they a) will tend to be rejected as inline by the compiler and b) even if they were inlined, are generally not going to provide any benefit



回答3:

It is necessarily treated by the compiler as a request for inline -- which it can ignore. There are some idioms for defining some functions in the header (e.g. empty virtual destructors) and some necessary header definitions (template functions), but other than that see GotW #33 for more information.

Some have noted that the compiler may even inline functions you never asked it to, but I'm not sure whether that would defeat the purpose of requesting to inline a function.



回答4:

It is indeed inlined - but any inline request can be ignored by the compiler.



回答5:

It is a request to the compiler that it can ignore.



回答6:

The 2003 ISO C++ standard says

7.1.2/2 A function declaration (8.3.5, 9.3, 11.4) 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/3 A function defined within a class definition is an inline
function. The inline specifier shall not appear on a block scope function declaration.

7.1.2/4 An inline function shall be defined in every translation unit in
which it is 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 defi-nition appears in the translation unit. ] If a function with external linkage is declared inline in one transla-tion 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 an
extern inline function is the same object in different translation
units.



回答7:

There are two things that shouldn't be lumped together:

  1. How you mark a function as being inline: define it with inline in front of the signature or define it at declaration point;
  2. What the compiler will treat such inline marking: regardless of how you marked the function as inline it will be treated as a request by the compiler.