5

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.

2
  • 4
    The standard says that it's an rvalue, i. e. that it has no storage. Now in practice, it's almost always implemented as an extra "0th" function parameter, but in theory a compiler could proceed to emitting code that calculates the address of the object every time it encounters this.
    – H2CO3
    Aug 29, 2014 at 4:56
  • 1
    You are wrong in believing that every local variable has a stack location. Some variables are only kept in registers. Aug 29, 2014 at 10:27

7 Answers 7

18

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.

1
  • 2
    Wow, I didn't know about -fverbose-asm, I shall praise your name from now on for letting me know it! (d'oh, and watch out for my upcoming compiler question...)
    – H2CO3
    Aug 29, 2014 at 5:10
13

The pointer this is not stored anywhere in relation to the class instance (because if you already have the class instance, getting its pointer is trivial!). Rather it behaves like a hidden argument that is always implicitly passed into member functions such as resize. (In some languages like Python this is passed explicitly.)

Note that the standard says nothing about where this is stored. You aren't allowed to take the address of this because it's not a variable. Hence your question concerns entirely an implementation detail.

As a concrete example,

class A
{
public:
  void fun(int x) { a = this + x; }
  A* a;
};

void foo(A& a)
{
  a.fun(1);
}

This is semantically equivalent to the following:

struct A
{
  A* a;
};
void A_fun(A* _this, int x) { _this->a = _this + x; }

void foo(A& a)
{
  A_fun(&a, 1);
}

So it is possible for a compiler to implement member functions in this way (or something similar). How an actual compiler implements it will vary, however.

5
  • In your example _this is stored in memory wherever it is declared, probably in main() somewhere when you declare your instance of A, or maybe it's a temporary. Supposing then that this is how the compiler "really does it", my question would be where does the compiler's "implicit" _this get instantiated?
    – quant
    Aug 29, 2014 at 4:02
  • But you sort of answered that with the last line; I guess I was hoping the standard would have some definition for this, becuase it has important implications in cache management, particularly false sharing.
    – quant
    Aug 29, 2014 at 4:02
  • 3
    No, this (or _this in the example) is a formal argument, it is not a local variable in main (or any other function) Aug 29, 2014 at 4:50
  • 3
    Where "this" is stored is the sort of thing that the C++ standard deliberately avoids specifying. That way the compiler writer can determine the most efficient implementation for the particular processor and operating system. In practice, it is very likely to be either on the stack or in a register. It is an ephemeral thing - it only needs to exist while the function is executing, and can be deleted as soon as the function returns.
    – Simon B
    Aug 29, 2014 at 12:47
  • in windows x86 cdecl this is stored in ecx register(this is faster, but since ecx is not accessible to C without assembly); with stdcall, it's stored on the stack as actual first(last to be pushed) argument. This allowed microsoft COM components to be usable from both C and c++ without having to use assembly to access this, or to pass this.
    – Dmytro
    Feb 23, 2018 at 4:35
2

Truth be told that there are various ways that a compiler can implement this, and it shouldn't matter to you which one is actually used. Yes, there may be some subtle interactions with the processor that would impact performance but the compiler writers almost certainly know about it way better than you do.

But the simplest approach is to simply treat this like it was any other parameter. So for a class like:

class Foo
{
    void bar();
    ...
};

Foo foo;
foo.bar();

The code that is produced is probably pretty much the same as the C equivalent of:

struct Foo
{
    ...
}

Foo_bar(Foo * foo) {
}

Foo foo;
Foo_bar(&foo);

So inside Foo::bar, this simply comes from being a hidden parameter to the method. In that respect, it works just like any other parameter.

However, you might want to know, where does the pointer come from in the first place? At some point in time the Foo object was created. It may have been created as a local variable, or perhaps via new. In either case, the program starts the creation of Foo by selecting the piece of memory to create the object in. It knows the correct address of Foo, because it selected or was given the piece of memory to put Foo into. It simply keeps track of that address for when it needs that pointer later.

5
  • OK, that makes sense, thanks. FYI 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 this pointer is stored might affect padding decisions.
    – quant
    Aug 29, 2014 at 4:50
  • @Arman, do you have reason to think that false sharing is going to be a problem for you? Aug 29, 2014 at 4:59
  • Yes. I am writing memory-bound performance critical code where cache misses are a huge concern. I don't have proof that this specifically is an issue, but I wanted to understand the implications first.
    – quant
    Aug 29, 2014 at 5:01
  • @Arman Don't want to draw consequences until you measured! The compiler storing or not storing this is probably not gonna cause the bottleneck anyway (4 bytes? 8?), but if it does, then switch to C. Or assembly.
    – H2CO3
    Aug 29, 2014 at 5:09
  • 1
    @Arman, its important to also note that the compiler may optimize your code the point that an object does not ever actually exist in memory at all. Its very hard to predict what exactly will end up happening. Your best bet is almost always to just make it work, then use profiling tools to find out what's slow. Its pretty much never what you think it will be. Aug 29, 2014 at 5:17
2

Arman, looking over your questions, I'd like to emphasize one aspect I think you're missing. Your instinct that the this pointer has to be stored somewhere is absolutely right. But, your mistake is in limiting the choices to "heap" and "stack". These are certainly common places for data to be stored, but there are others (and there are other besides these!):

  • CPU registers
  • "the global section"
  • thread-local storage

When arguments are passed to a function, usually the first "couple" arguments or so are placed in CPU registers. The details vary depending on many things: the processor architecture (x86 vs ARM vs ARM64 vs ...), the number of arguments, the types and sizes of the arguments (integers, pointers, floats, vector types), and on certain code annotations the function may have (which you're rarely going to have to deal with).

In almost every processor you're likely to program for, the 'this' pointer will be passed as the implicit 0th argument of a member function, which means it will be passed via a CPU register. In x86_64 that is register ECX, and in ARM that would be register r0.

1

It depends on the calling convention of the compiler but usually it's passed as the first (hidden) argument and not stored in A anywhere. The first argument is then either passed as i a register or on the stack.

3
  • I'm not asking how it's passed into functions, I'm asking where it comes from, and where its contents is stored.
    – quant
    Aug 29, 2014 at 0:11
  • The variable that refers to the object is "this." In your example, vec holds the address of this. When you call resize, the value of vec is passed as the first parameter. The answer given here is both correct and relevant.
    – dave
    Aug 29, 2014 at 0:52
  • @dave yes but my question was about where the contents of this is stored, not where the instance to which the memory address referred to by this is stored.
    – quant
    Aug 29, 2014 at 0:57
1

Annotating your example:

main()
{
  std::vector<A> vec;
  vec.resize(100); // What really happens: vec.resize(&vec, 100);
}

The compiler emits code that calculates the address of the class instance vec and passes it as the first parameter to any method call against that instance. There is no global variable 'this'. There is no member variable 'this', there is just an address passed as a formal parameter to a method call. You can refer to it in your method body just like any other parameter.

6
  • So where is the value of that address, which is passed on to the method, stored?
    – quant
    Aug 29, 2014 at 4:24
  • It is calculated at runtime, just like any other address. Are you familiar with the & operator? Aug 29, 2014 at 4:26
  • Yes, I am. I know it's calculated at runtime, but where is it stored?
    – quant
    Aug 29, 2014 at 4:27
  • To put it more simply, suppose this happens to have a value of 0x28ac67. Where is that value stored in your program?
    – quant
    Aug 29, 2014 at 4:29
  • 2
    It is not stored in the program (which is a static thing, e.g. an ELF executable file on Linux) but it appears -in a register of the processor- dynamically at execution time. Aug 29, 2014 at 4:52
-2

It sounds like you want to know where the contents of an instance of the class are stored. The answer is, it depends.

Classes can be instantiated on the stack, on the heap, or indirectly on the heap as in your vector example.

In your vector example, following the vec.resize(100), there are 100 instances of class A constructed in the memory reserved by the vector vec. The memory for the vector vec is allocated on the heap. Hence, the instances of a are indirectly stored in the heap.

About this

this is quite simply the address of an instance of the class. There can be many instances of a class. In your example, there are 100 instances of class A, each with their own this. The this for an instance is not stored anywhere. It is just the address of the instance.

For example, call vec[3].fun(), and the a member of the instance of class A at the third location of vector vec will be a pointer to the instance of class A at the fourth location of vector vec. (Of course, you can in turn, call fun() using the member variable a.)

The value of this, within a method call is determined by the caller of the method. The pointer to the instance at the time of the method call becomes the this pointer to the method call.

2
  • 1
    The this for an instance is not stored anywhere - This is clearly not true, but it is the crux of the question.
    – quant
    Aug 29, 2014 at 3:59
  • Heh, you can deny all you want. :-)
    – Bill Door
    Aug 29, 2014 at 15:30

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.