Search code examples
c++inlinepimpl-idiom

Are methods in the pimpl inlined?


Considering next simple example:

The header:

// a.hpp
#ifndef A_HPP
#define A_HPP
#include <memory>

class A
{
 public:
  A();

  int foo();

 private:
  struct Imp;
  std::auto_ptr< Imp > pimpl;
};

#endif // A_HPP

The implementation :

// a.cpp
#include "a.hpp"

struct A::Imp
{
 int foo()
 {
  // do something and return the result
 }
};

A::A() : pimpl( new Imp )
{}
int A::foo()
{
  return pimpl->foo();
}

The main :

// main.cpp
#include "header.hpp"
int main()
{
  A a;
  return a.foo();
}

The questions are :
Is the method A::Imp::foo going to get inlined into A::foo?
Does it depend on the implementation what is in that method?

PS I am using gcc (4.3.0 if it matters).

EDIT

I guess I didn't explain very well. What I exactly meant is this. If I use the maximum optimization level, is the // do something and return the result going to be placed in the A::foo() or A::Imp::foo()?
Without optimization, I see that this is not done (the pimpl->foo() is still called).

I understand that A::foo() will never get inlined in main(), but that is not what I am asking.


Solution

  • Herb Sutter once made a great article about inlining.

    The first question to ask is: when can inlining happen ?

    In C++:

    • it may happen at the compilation stage
    • it may happen at the link stage (LTO: Link Time Optimization)

    Both times, the mechanism is similar: if the compiler/linker knows about the implementation of the method, it may decide to copy/paste the implementation in place of emitting a call. This decision is based on complex heuristics, and I only know they exist, not what they are about.

    The critical point is therefore the knows about the implementation bit.

    • for the compiler: it means defined in the same translation unit
    • for the linker: it means defined in one of the translation units being linked OR in a static library it will linked to... afaik it won't be optimized if the method resides in a DLL

    So here: yes, the call pimpl->foo() may be inlined within A::foo. It will depend on both the compiler and the compiling options.

    For gcc/clang, if A::Impl::foo is small enough, it could be optimized from O1 onward (unless you pass -fno-inline).