C++ – Where is the ‘this’ Variable Stored?

c

Let's take this simple c++ program as an example:

#include <vector>
class A
{
  void fun() { a = this + 1; }
  A* a;
};

main()
{
  std::vector<A> vec;
  vec.resize(100);
}

Forgetting for the moment that this is a pointer to some instantiation of A, this question is about the variable this itself, and where its contents (the value of the memory address) is stored.

It can't be a literal because the compiler can't know the location of class A, so its contents must be allocated somewhere on the stack or heap as a variable. In this case the instances of A are allocated on the heap; does this mean the this pointer is also on the heap?

Looking at the resize call of vec, a compiler might do something like this under the hood:

std::vector<A>::resize(this, 100); // where 'this' is a pointer to vec

So my question is, where does the this pointer come from? Ie. where is the contents of this (the 32/64-bit memory address value) stored in memory for it to be passed to this method?

I would presume it can't be a normal member; so my first thought was that it's a mangled global variable of some sort, but then by storing an unknown number of them in a vector I don't see how the compiler could achieve this either. Where is the contentx of the this variable stored in relation to the contents of the A class member to which it refers?

If the standard has something to say about this, I would prefer an answer with reference to the standard.

Note that the reason I want to know is because I am concerned about false sharing of the memory allocated for the this object if I modify member variables. Knowledge of where the this object is stored might affect padding decisions.

Best Answer

The point is that this is an implicit formal parameter (containing the address of the object whose method you are calling). It is not a local variable.

Look at the generated code of your program. I compiled (on Linux/Debian/Sid/x86-64 with GCC 4.9.1) your example arman.cc with

  gcc -O1 -fverbose-asm -S arman.cc

and got the function main below

         .globl  main
         .type   main, @function
 main:
 .LFB512:
         .cfi_startproc
         .cfi_personality 0x3,__gxx_personality_v0
         .cfi_lsda 0x3,.LLSDA512
         pushq   %rbx    #
         .cfi_def_cfa_offset 16
         .cfi_offset 3, -16
         subq    $48, %rsp       #,
         .cfi_def_cfa_offset 64
         movq    $0, 16(%rsp)    #, MEM[(struct _Vector_impl *)&vec]._M_start
         movq    $0, 24(%rsp)    #, MEM[(struct _Vector_impl *)&vec]._M_finish
         movq    $0, 32(%rsp)    #, MEM[(struct _Vector_impl *)&vec]._M_end_of_storage
         movq    $0, (%rsp)      #, MEM[(struct A *)&__x]
         movq    %rsp, %rcx      #,
         movl    $100, %edx      #,
         movl    $0, %esi        #,
         leaq    16(%rsp), %rdi  #, tmp92
 .LEHB0:
         call    _ZNSt6vectorI1ASaIS0_EE14_M_fill_insertEN9__gnu_cxx17__normal_iteratorIPS0_S2_EEmRKS0_  #
 .LEHE0:
         movq    16(%rsp), %rdi  # MEM[(struct _Vector_base *)&vec]._M_impl._M_start, D.10014
         testq   %rdi, %rdi      # D.10014
         je      .L34    #,
         call    _ZdlPv  #
         jmp     .L34    #
 .L33:
         movq    %rax, %rbx      #, tmp91
         movq    16(%rsp), %rdi  # MEM[(struct _Vector_base *)&vec]._M_impl._M_start, D.10014
         testq   %rdi, %rdi      # D.10014
         je      .L32    #,
         call    _ZdlPv  #
 .L32:
         movq    %rbx, %rdi      # tmp91,
 .LEHB1:
         call    _Unwind_Resume  #
 .LEHE1:
 .L34:
         movl    $0, %eax        #,
         addq    $48, %rsp       #,
         .cfi_def_cfa_offset 16
         popq    %rbx    #
         .cfi_def_cfa_offset 8
         ret
         .cfi_endproc

You see that some space for your vec is allocated on the stack (e.g. with subq $48, %rsp etc...) and then the address of that zone on the stack is passed as the this formal argument (using the usual x86-64 ABI conventions, which dictates (p 20) that the first argument of function is passed thru register %rdi) so you could say that this is, at the beginning of some member function, in the register %rdi ...

IIRC, the wording of the C++ standard are vague enough to permit the this argument to be passed in a special way, but all the ABIs I heard of are passing it exactly as the first (pointer) argument of usual C functions.

BTW, you should trust the compiler and let it pass this as convenient and as prescribed by ABI specifications.

Related Topic