Original link
When we talk about pointers, it is often assumed that it is something that can be represented by a void *
pointer, which x86_64
is 8 bytes in size under a platform. For example, here is an excerpt from the x86_64
article on Wikipedia:
Pushes and pops on the stack are always in 8-byte strides, and pointers are 8 bytes wide.
From CPU
the point of view, the pointer is nothing more than the memory address, all the memory address x86_64
under the platform is represented by 64 bits, so assume that it is 8 bytes is correct. It is not difficult to verify what we say by simply outputting the lengths of different types of pointers.
#include <iostream>int main() { std::cout << "sizeof(int*) == "sizeof(int"\n" "sizeof(double*) == "sizeof(double"\n" "sizeof(void(*)()) == "sizeof(voidstd::endl;}
Compile and run the above program, from the results can be seen all the length of the pointer is 8 bytes:
$ uname -ix86_64$ g++ -Wall ./example.cc$ ./a.outsizeof(int*) 8sizeof(double*) 8sizeof(void8
There is, however, a C++
special case-a pointer to the member function . It's interesting, the member function pointer is twice times the length of any other pointer . This can be verified by the following simple program, the result of the output is 16
:
#include <iostream>struct Foo { voidconst { }};int main() { std::coutsizeofstd::endl;}
Does this mean that Wikipedia is wrong? Obviously not! From a hardware point of view, all pointers are still 8 bytes. So, what is the pointer to the member function? This is a C++
language feature, where pointers to member functions are not mapped directly to hardware, and are implemented by the runtime (compiler), which can incur some additional overhead, often resulting in a loss of performance. The C++
language specification does not refer to the implementation details, nor does it explain this type of pointer. Fortunately, the Itanium C++ ABI
specification shares the C++
details of the runtime implementation--for example, it explains Virtual Table
RTTI
how, and how the exception is implemented, and §2.3
also explains the member pointers:
A pointer toMemberfunction isA pair asFollows:ptr: forA non-virtualfunction, this field isA simplefunctionPointer. forA virtualfunction, it is 1Plus the virtual table offset (inchbytes ofThefunction, represented asA ptrdiff_t. The value zero represents a NULL pointer, Independent ofThe adjustment field value below.adj:The required adjustment toThis, represented asA ptrdiff_t.
Therefore, a member pointer is a 16
byte 8
, not a byte, because after a simple function pointer you also need to save information about how to adjust this
the pointer (which is always passed implicitly to the non-static member function). The ABI
specification does not say why and when the pointer needs to be adjusted this
. It may not be obvious at first, let's look at the following examples of class inheritance:
struct A {void foo () const {} char Pad0[32 ];}; struct B {void Bar () const {} char pad2[64 ];}; struct C:a, b{};
A
And B
both have a non-static member function and a data member. These two methods can be used to access this
data members in their classes by implicitly passing pointers to them. To access any data member, you need to this
add an offset to the pointer, which is the offset of the data member to the base address of the class object , which can be ptrdiff_t
represented by. However, things will become more complex in multiple succession. We have a class C
A
that inherits and B
, what will happen? The compiler puts A
and B
puts the values of the pointers in memory, B
A
below, so that the methods of the A
class and B
the methods of the class see a different this
value. This can be verified by practice, such as:
#include <iostream>structAvoidFoo ()Const{STD::cout<<"A ' s This:"<< This<<STD:: Endl; }Charpad0[ +];};structb{voidBar ()Const{STD::cout<<"B ' s This:"<< This<<STD:: Endl; }Charpad2[ -];};structC:a, B {};intMain () {C obj; Obj.foo (); Obj.bar (); }
$ g++-Wall-o./test.&&./testA‘s this: 0x7fff57ddfb48B‘0x7fff57ddfb68
As you can see, the value of the this
pointer is passed to B
a method that is A
larger than the method--the 32
actual size of a class A
object. But what happens when we use the following function to invoke a method of a class using a pointer C
?
void call_by_ptr(constvoidconst) { (obj.*mem_func)();}
In relation to what functions are called, different this
pointer values are passed to these functions. But the call_by_ptr
function does not know whether its arguments are foo()
pointers or bar()
pointers, and the only time that the information can be known is when these methods are used. This is why the pointer to the member function needs to know how to adjust the pointer before calling this
. Now, we put all of them into a simple program that illustrates the mechanism of internal work:
#include <iostream>structAvoidFoo ()Const{STD::cout<<"A ' s this:\t"<< This<<STD:: Endl; }Charpad0[ +];};structBvoidBar ()Const{STD::cout<<"B ' s this:\t"<< This<<STD:: Endl; }Charpad2[ -];};structC:a, b{};voidCall_by_ptr (ConstC &obj,void(C::* mem_func) ()Const){void*data[2];STD::memcpy(Data, &mem_func,sizeof(Mem_func));STD::cout<<"------------------------------\ n" "Object ptr:\t"<< &obj <<"\nfunction ptr:\t"<< data[0] <<"\npointer adj:\t"<< data[1] <<STD:: Endl; (Obj.*mem_func) ();}intMain () {C obj; Call_by_ptr (obj, &c::foo); Call_by_ptr (obj, &c::bar);}
------------------------------Object ptr: 0x7fff535dfb28Function ptr: 0x10c620cacPointer adj: 0A‘s this: 0x7fff535dfb28------------------------------Object ptr: 0x7fff535dfb28Function ptr: 0x10c620cfePointer adj: 0x20B‘s this: 0x7fff535dfb48
Why is the function pointer in C + + 16 bytes