Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>It seems like your question was simply this: What's the difference between calling "ptr->something()" and "instance.something()?"</p> <p>From the perspective of function "something", absolutely nothing.</p> <pre><code>#include &lt;iostream&gt; struct Foo { void Bar(int i) { std::cout &lt;&lt; i &lt;&lt; "\n"; } }; int main() { Foo concrete; Foo* dynamic = new Foo; concrete.Bar(1); dynamic-&gt;Bar(2); delete dynamic; } </code></pre> <p>The compiler only emits one instance of Foo::Bar() which has to handle both cases, so there <em>can't</em> be any difference.</p> <p>The only changes, if any, are at the call site. When invoking <code>dynamic-&gt;Bar()</code> the compiler will emit code equivalent to <code>this = dynamic; call Foo0Bar</code> to transfer the value of "dynamic" directly into wherever "this" is held (register/address). In the case of <code>concrete.Bar</code>, concrete will be on the stack, so it will emit slightly different code to load a stack offset into the same register/memory location and make the call. The function itself will have no way to tell.</p> <p>---- EDIT ----</p> <p>Here's the assembly from "g++ -Wall -o test.exe -O1 test.cpp &amp;&amp; objdump -lsD test.exe | c++filt" with the above code, focusing on main:</p> <pre><code>main(): 400890: 53 push %rbx 400891: 48 83 ec 10 sub $0x10,%rsp 400895: bf 01 00 00 00 mov $0x1,%edi 40089a: e8 f1 fe ff ff callq 400790 &lt;operator new(unsigned long)@plt&gt; 40089f: 48 89 c3 mov %rax,%rbx 4008a2: be 01 00 00 00 mov $0x1,%esi 4008a7: 48 8d 7c 24 0f lea 0xf(%rsp),%rdi 4008ac: e8 47 00 00 00 callq 4008f8 &lt;Foo::Bar(int)&gt; 4008b1: be 02 00 00 00 mov $0x2,%esi 4008b6: 48 89 df mov %rbx,%rdi 4008b9: e8 3a 00 00 00 callq 4008f8 &lt;Foo::Bar(int)&gt; 4008be: 48 89 df mov %rbx,%rdi 4008c1: e8 6a fe ff ff callq 400730 &lt;operator delete(void*)@plt&gt; 4008c6: b8 00 00 00 00 mov $0x0,%eax 4008cb: 48 83 c4 10 add $0x10,%rsp 4008cf: 5b pop %rbx 4008d0: c3 retq </code></pre> <p>Our member function calls are here:</p> <p>concrete.Bar(1)</p> <pre><code>4008a2: be 01 00 00 00 mov $0x1,%esi 4008a7: 48 8d 7c 24 0f lea 0xf(%rsp),%rdi 4008ac: e8 47 00 00 00 callq 4008f8 &lt;Foo::Bar(int)&gt; </code></pre> <p>dynamic->Bar(2)</p> <pre><code>4008b1: be 02 00 00 00 mov $0x2,%esi 4008b6: 48 89 df mov %rbx,%rdi 4008b9: e8 3a 00 00 00 callq 4008f8 &lt;Foo::Bar(int)&gt; </code></pre> <p>Clearly "rdi" is being used to hold "this", and the first uses a stack-relative address (since <code>concrete</code> is on the stack) and the second simply copies the value of "rbx", which has the return value from "new" earlier on (<code>mov %rax,%rbx</code> after the call to new)</p> <p>---- EDIT 2 ----</p> <p>Beyond the function call itself, speaking to the actual operations that have to occur constructing, tearing down and accessing-values-within objects, the stack is generally faster.</p> <pre><code>{ Foo concrete; foo.Bar(1); } </code></pre> <p>generally takes less cycles than</p> <pre><code>Foo* dynamic = new Foo; dynamic-&gt;Bar(1); delete dynamic; </code></pre> <p>because the second variant has to allocate memory and, in general, memory allocators are slow (they typically have some kind of lock in them to manage a shared memory pool). Also, the memory allocated for this may be cache-cold (although most stock allocators will write block data to the page causing it to become somewhat cache-warm by the time you get around to using it, but that may induce a page fault, or push something else out of cache).</p> <p>Another potential advantage of using the stack is general cache coherence.</p> <pre><code>int i, j, k; Foo f1, f2, f3; // ... thousands of operations populating those values f1.DoCrazyMagic(f1, f2, f3, i, j, k); </code></pre> <p>If there are no external references inside <code>DoCrazyMagic</code>, then all operations will happen within a small memory locality. Conversely, if we do</p> <pre><code>int *i, *j, *k; Foo *f1, *f2, *f3; // ... thousands of operations populating those values f1-&gt;DoCrazyMagic(*f1, *f2, *f3, *i, *j, *k); </code></pre> <p>It is conceivable that in a complex scenario the variables will be spread out across multiple-pages and may incur multiple page faults.</p> <p>However - if the "thousands of operations" are intense and complex enough, the stack area where we put <code>i, j, k, f1, f2 and f3</code> might no-longer be "hot".</p> <p>Put another way: If you abuse the stack, it also becomes a contested resource and the advantages over heap usage become marginalized or eliminated.</p>
    singulars
    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.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      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