Note that there are some explanatory texts on larger screens.

plurals
  1. POInterface reference to local implementation
    primarykey
    data
    text
    <p>Please consider the following code:</p> <pre><code>struct A { virtual ~A() {} virtual int go() = 0; }; struct B : public A { int go() { return 1; } }; struct C : public B { int go() { return 2; } }; int main() { B b; B &amp;b_ref = b; return b_ref.go(); } </code></pre> <p>Under GCC 4.4.1 (using <code>-O2</code>), the call to <code>B::go()</code> gets inlined (ie., no virtual dispatch happens). That means the compiler acknowledges <code>a_ref</code> indeed points to a <code>B</code> type variable. A <code>B</code> reference can be used to point to a <code>C</code>, but the compiler is smart enough to foresee this is not the case, so it totally optimizes away the function call, inlining the function.</p> <p><em>Great!</em> That's an incredible optimization.</p> <p>But, then, why doesn't GCC do the same in the following case?</p> <pre><code>struct A { virtual ~A() {} virtual int go() = 0; }; struct B : public A { int go() { return 1; } }; struct C : public B { int go() { return 2; } }; int main() { B b; A &amp;b_ref = b; return b_ref.go(); // B::go() is not inlined here, and a virtual dispatch is issued } </code></pre> <p>Any ideas? What about other compilers? Is this kind of optimization common? (I'm very new into this kind of compiler insight, so I'm curious)</p> <p>If the second case worked I could create some really great templates, like these:</p> <pre><code>template &lt;typename T&gt; class static_ptr_container { public: typedef T st_ptr_value_type; operator T *() { return &amp;value; } operator const T *() const { return &amp;value; } T *operator -&gt;() { return &amp;value; } const T *operator -&gt;() const { return &amp;value; } T *get() { return &amp;value; } const T *get() const { return &amp;value; } private: T value; }; template &lt;typename T&gt; class static_ptr { public: typedef static_ptr_container&lt;T&gt; container_type; typedef T st_ptr_value_type; static_ptr() : container(NULL) {} static_ptr(container_type *c) : container(c) {} inline operator st_ptr_value_type *() { return container-&gt;get(); } inline st_ptr_value_type *operator -&gt;() { return container-&gt;get(); } private: container_type *container; }; template &lt;typename T&gt; class static_ptr&lt;static_ptr_container&lt;T&gt;&gt; { public: typedef static_ptr_container&lt;T&gt; container_type; typedef typename container_type::st_ptr_value_type st_ptr_value_type; static_ptr() : container(NULL) {} static_ptr(container_type *c) : container(c) {} inline operator st_ptr_value_type *() { return container-&gt;get(); } inline st_ptr_value_type *operator -&gt;() { return container-&gt;get(); } private: container_type *container; }; template &lt;typename T&gt; class static_ptr&lt;const T&gt; { public: typedef const static_ptr_container&lt;T&gt; container_type; typedef const T st_ptr_value_type; static_ptr() : container(NULL) {} static_ptr(container_type *c) : container(c) {} inline operator st_ptr_value_type *() { return container-&gt;get(); } inline st_ptr_value_type *operator -&gt;() { return container-&gt;get(); } private: container_type *container; }; template &lt;typename T&gt; class static_ptr&lt;const static_ptr_container&lt;T&gt;&gt; { public: typedef const static_ptr_container&lt;T&gt; container_type; typedef typename container_type::st_ptr_value_type st_ptr_value_type; static_ptr() : container(NULL) {} static_ptr(container_type *c) : container(c) {} inline operator st_ptr_value_type *() { return container-&gt;get(); } inline st_ptr_value_type *operator -&gt;() { return container-&gt;get(); } private: container_type *container; }; </code></pre> <p>These templates could be used to avoid virtual dispatch in many cases:</p> <pre><code>// without static_ptr&lt;&gt; void func(B &amp;ref); int main() { B b; func(b); // since func() can't be inlined, there is no telling I'm not // gonna pass it a reference to a derivation of `B` return 0; } // with static_ptr&lt;&gt; void func(static_ptr&lt;B&gt; ref); int main() { static_ptr_container&lt;B&gt; b; func(b); // here, func() could inline operator-&gt;() from static_ptr&lt;&gt; and // static_ptr_container&lt;&gt; and be dead-sure it's dealing with an object // `B`; in cases func() is really *only* meant for `B`, static_ptr&lt;&gt; // serves both as a compile-time restriction for that type (great!) // AND as a big runtime optimization if func() uses `B`'s // virtual methods a lot -- and even gets to explore inlining // when possible return 0; } </code></pre> <p>Would it be practical to implement that? (and don't go on saying it's a micro-optimization because it may well be a huge optimization..)</p> <p>-- edit</p> <p>I just noticed the problem with <code>static_ptr&lt;&gt;</code> has nothing to do with the problem I exposed. The pointer type is kept, but it still doesn't inline. I guess GCC just doesn't go as deep as needed to find out static_ptr_container&lt;>::value is not a reference nor pointer. Sorry about that. But the question still remains unanswered.</p> <p>-- edit</p> <p>I've worked out a version of <code>static_ptr&lt;&gt;</code> that actually works. I've changed the name a bit, also:</p> <pre><code>template &lt;typename T&gt; struct static_type_container { // uncomment this constructor if you can't use C++0x template &lt;typename ... CtorArgs&gt; static_type_container(CtorArgs ... args) : value(std::forward&lt;CtorArgs&gt;(args)...) {} T value; // yes, it's that stupid. }; struct A { virtual ~A() {} virtual int go() = 0; }; struct B : public A { int go() { return 1; } }; inline int func(static_type_container&lt;Derived&gt; *ptr) { return ptr-&gt;value.go(); // B::go() gets inlined here, since // static_type_container&lt;Derived&gt;::value // is known to be always of type Derived } int main() { static_type_container&lt;Derived&gt; d; return func(&amp;d); // func() also gets inlined, resulting in main() // that simply returns 1, as if it was a constant } </code></pre> <p>The only weakness is that the user has to access <code>ptr-&gt;value</code> to get the actual object. Overloading <code>operator -&gt;()</code> doesn't work in GCC. Any method returning a reference to the actual object, if it it's inline, breaks the optimization. What a pity..</p>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload