views:

101

answers:

1

I have the following code:

#include <boost/shared_ptr.hpp>

struct Foo { int a; };
static int A;

void
func_shared(const boost::shared_ptr<Foo> &foo) {
    A = foo->a;
}

void
func_raw(Foo * const foo) {
    A = foo->a;
}

I thought the compiler would create identical code, but for shared_ptr version an extra seemingly redundant instruction is emitted.

Disassembly of section .text:

00000000 <func_raw(Foo*)>:
   0:   55                      push   ebp
   1:   89 e5                   mov    ebp,esp
   3:   8b 45 08                mov    eax,DWORD PTR [ebp+8]
   6:   5d                      pop    ebp
   7:   8b 00                   mov    eax,DWORD PTR [eax]
   9:   a3 00 00 00 00          mov    ds:0x0,eax
   e:   c3                      ret
   f:   90                      nop

00000010 <func_shared(boost::shared_ptr<Foo> const&)>:
  10:   55                      push   ebp
  11:   89 e5                   mov    ebp,esp
  13:   8b 45 08                mov    eax,DWORD PTR [ebp+8]
  16:   5d                      pop    ebp
  17:   8b 00                   mov    eax,DWORD PTR [eax]
  19:   8b 00                   mov    eax,DWORD PTR [eax]
  1b:   a3 00 00 00 00          mov    ds:0x0,eax
  20:   c3                      ret

I'm just curious, is this necessary, or it is just an optimizer's shortcoming?

Compiling with g++ 4.1.2, -O3 -NDEBUG.

+7  A: 

It's not a 'redundant' instruction.

The relevant section of the first code snippet is equivalent to: *p

Whilst in the second it's equivalent to: **p

Due to shared_ptr's internals there is a second level of indirection. This is not something the optimizer can 'fix'.

At any rate, the difference is negligible.

EDIT:

Whoops! My apologies, I misread your code.

You are passing the shared_ptr BY REFERENCE in your code. That will pass it "by pointer" at the ASM level.

So you're passing a pointer to a shared_ptr, and that shared_ptr contains a pointer to your object.

Hence the two levels of indirection.

Sorry for the confusion. :)

RaptorFactor
Hmmm, it seems that boost's implementation actually contains object's pointer directly in its body, so the second level of indirection is only used when incrementing/decrementing reference count (accessing shared ref.counter structure). Accessing a pointer should only be a single indirection.
Alex B
You are correct, I misread.The second level of indirection is caused by the shared_ptr being passed by reference.
RaptorFactor
Nice catch, there.
Andres Jaan Tack
Yes, that, indeed, seems to be the case!
Alex B