0

Why, in the following code, compiler, knowing exact type, can't inline virtual function?

https://goo.gl/AgvefX

using namespace std;

struct Base{
    void fire(){
        show();
    }

    virtual void show() =0;/*{
        cout << "base";
    }*/
};

struct A : Base{
    inline __attribute__((__always_inline__)) void show() {
        cout << "a";
    }
};

int main() {
    A a;
  for (int i=0;i<1000;i++){
    a.fire();
  }
    //a.fire();

    return 0;
}

Can I do something about this, without CRTP?

tower120
  • 5,007
  • 6
  • 40
  • 88

1 Answers1

4

I'm not good at reading assembler code, but the way I see your example, when in main:

  1. 1000 is loaded into a register
  2. 1 is substracted,
  3. the address of "a" is loaded and
  4. the output operator is called before the
  5. jump back to the beginning of the loop.

I don't see a call to fire or show. It keeps the implementation for show, but it is not used. That is correct because it has external linkage.

If you put everything in an anonymous namespace, the implementation can be omitted.

Could you put your reasoning with the assembler code in your question? For reference, here is the generated assembler code from the provides link:

.LC0:
    .string "a"
A::show():
    movl    $1, %edx
    movl    $.LC0, %esi
    movl    std::cout, %edi
    jmp std::basic_ostream<char, std::char_traits<char> >& std::__ostream_insert<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*, long)
main:
    pushq   %rbx
    movl    $1000, %ebx
.L3:
    movl    $1, %edx
    movl    $.LC0, %esi
    movl    std::cout, %edi
    call    std::basic_ostream<char, std::char_traits<char> >& std::__ostream_insert<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*, long)
    subl    $1, %ebx
    jne .L3
    xorl    %eax, %eax
    popq    %rbx
    ret
    subq    $8, %rsp
    movl    std::__ioinit, %edi
    call    std::ios_base::Init::Init()
    movl    $__dso_handle, %edx
    movl    std::__ioinit, %esi
    movl    std::ios_base::Init::~Init(), %edi
    addq    $8, %rsp
    jmp __cxa_atexit
Jens
  • 9,058
  • 2
  • 26
  • 43
  • You're right it's inlined indeed. There is just excess code with A::show() which is never called. Here is how it should be https://goo.gl/hZ3qE3 – tower120 Sep 27 '15 at 22:28
  • @tower120 It is external, and might be called elsewhere. – vonbrand Sep 27 '15 at 23:43
  • @tower120 I think the compiler is right because the function has external linkage. It could be called from another compilation unit. You can put it in an anonymous namespace, or - I have not tested it - use whole-program optimization switch for gcc. – Jens Sep 28 '15 at 05:08