c++inlinevirtual-functionsnon-virtual-interface

Using the non-virtual-interface idiom, can/will my non-virtual function be inlined ?


I recently decided to use the non-virtual interface idiom (NVI) to design an interface in C++, mostly for the purpose of using a parameter with a default value (thus avoiding problems caused by the fact that default parameters are statically bound).

I came with a rather trivial declaration for my class, looking like this :

class Interface{

public:
    void func(Parameter p = 0);
    virtual ~Interface();
private:
    virtual void doFunc(Parameter p)=0;

};

void Interface::func(Parameter p){ doFunc(p); }
Interface::~Interface() {}

I know that providing the function body in a header automatically mark a function as candidate for inlining (though I don't know if placing the definition outside of the class will prevent that). I also know that virtual function aren't inlined for obvious reasons (we don't know which function will be called at runtime, so we can't replace calls by the function's body obviously).

Then, in this case, will func() be marked candidate for inlining ? It isn't a virtual function, but still calls a virtual function. Does it make it inline-able ?

Extra question: would it be worth it ? The body consist of only one statement.

Note that this question is quite rather for learning about it rather than searching optimization everywhere. I know that this function will be called only a few time (well, for now, so might as well be prudent as to how the program evolves), and that inlining would be quite superfluous and not the main concern about my program's performance.

Thanks !


Solution

  • I know that providing the function body in a header automatically mark a function as candidate for inlining

    More or less; but you do that by providing the function body in a class definition, or by explicitly declaring it inline if it's in a header. Otherwise, the function is subject to the One Definition Rule, and you'll get errors if you include the header in more than one translation unit.

    Note that this doesn't force the compiler to inline all calls to the function; providing the definition in a header just allows it to inline it in any translation unit that includes the header, if it thinks it's worth it. Also, some compilers can perform "whole program optimisation", and inline functions even when a definition is not available at the call site.

    Then, in this case, will func() be marked candidate for inlining ? It isn't a virtual function, but still calls a virtual function. Does it make it inline-able ?

    Yes, all functions are candidates for inlining. If they call themselves, then obviously you couldn't inline all the calls; nor if the function isn't known at compile time (e.g. because it must be called virtually, or through a function pointer). In this case, inlining the function would replace the direct call to func() with a virtual call to doFunc().

    Note that sometimes virtual calls can be inlined, if the dynamic type is known at compile time. For example:

    struct MyImplementation : Interface {/*whatever*/};
    MyImplementation thing;
    thing.func(); // Known to be MyImplementation, func and doFunc can be inlined
    

    Extra question: would it be worth it ?

    That depends on what "it" is. If you mean compile time then, as long as the function remains short, you might get some benefit (possibly significant, if the function is called many times) for negligible cost. If you mean the cost of spending time choosing where to put it, then probably not; just put it wherever's most convenient.