none
about virtual mechanism does not work with "(&object)->foo()"

    Question

  • class base{
    public:
     virtual void f() {
      std::cout<<"base::f()"<< std::endl;
     }
    };
    class derived: public base{
    public:
     void f() {
      std::cout<<"derived::f()"<< std::endl;
     }
    };
    void main()
    {
     base b;
     (&b)->f();
     (&b)->~base();
     new(&b) derived;
     (&b)->f();  // 1
     base *pb = &b;
     pb->f();    // 2
    }

     

    In above code snippet. Intuitively, I thought "// 1" and "// 2" will all call derived::foo(). Actually, "//1" calls base::foo(). I checked its assemble code, it seems the compiler uses static linkage rather than dynamic linkage. So is it a optimization of compiler to treat (&b)->foo() as b.foo() or a criterion from c++ standard?

    Tuesday, November 06, 2007 7:38 AM

Answers

  • If you look at the C and C++ Standards you'll see that p->member is defined in term of (*p).member so given:

    Code Block
    (&b)->f();

     

    The compiler will internally convert this to:

    Code Block
    (*(&b)).f();

     

     

    Which it will then trivially reduce to:

    Code Block
    b.f();

     

     

    Then as the compiler knows that b is a local variable who static type is base it de-virtualizes the call to f().

     

    Note: I suspect that we could make the compiler stricter here and only perform the de-virtualization if b is a local variable that was not initialized via placement-new (i.e. it was initialized normally) - but then again this is not a coding style that I would wish to encourage.

    Tuesday, November 06, 2007 6:02 PM
    Moderator

All replies

  • I'm not a 100% clear on the rules here, but I imagine the compiler ignores the fact that you're pulling a temporary pointer.

    One point worth noting, though; the above code would swiftly cross into the undefined behavior domain, should you introduce any variables (or secondary vtables) in derived.
    Tuesday, November 06, 2007 9:37 AM
    Moderator
  • If you look at the C and C++ Standards you'll see that p->member is defined in term of (*p).member so given:

    Code Block
    (&b)->f();

     

    The compiler will internally convert this to:

    Code Block
    (*(&b)).f();

     

     

    Which it will then trivially reduce to:

    Code Block
    b.f();

     

     

    Then as the compiler knows that b is a local variable who static type is base it de-virtualizes the call to f().

     

    Note: I suspect that we could make the compiler stricter here and only perform the de-virtualization if b is a local variable that was not initialized via placement-new (i.e. it was initialized normally) - but then again this is not a coding style that I would wish to encourage.

    Tuesday, November 06, 2007 6:02 PM
    Moderator
  •  

    Thanks for your reply.

     

    These code comes from a interview examination. I don't want to comment on author's intention. Smile But the result is realy out of my anticipation.

     

    So, as you said, the virtualization here could work or could not, it is just a behavior of specific compiler?

    Wednesday, November 07, 2007 1:36 AM