6

Normally pointers contain addresses. Why do pointers to member of a class contain offsets?

Talking about pointers to class data members, not pointers to member functions.

templatetypedef
  • 362,284
  • 104
  • 897
  • 1,065
Nitesh
  • 303
  • 1
  • 5
  • 6
    because it does not make sense otherwise – Sopel Jul 26 '17 at 17:39
  • Can you give a more specific example, especially in terms of code you don't understand? Are you asking about [this situation](https://stackoverflow.com/questions/670734/c-pointer-to-class-data-member)? – tadman Jul 26 '17 at 17:40
  • 2
    What else would it contain? – Kerrek SB Jul 26 '17 at 17:41
  • A pointer-to-data-member is a transform from an object address to a member subobject address. How do you think that transform works? What is the relationship between these two addresses? – Ben Voigt Jul 26 '17 at 17:42
  • @KerrekSB: Lots of stuff if it has to work with virtual inheritance... – Ben Voigt Jul 26 '17 at 17:42
  • 1
    @anatolyg: That's about functions, while I'm pretty sure this question concerns data members. – Ben Voigt Jul 26 '17 at 17:44
  • You need to go back and understand the C++ object model. Otherwise you won't finish your homework. – rlbond Jul 26 '17 at 17:45
  • 1
    You may want to look at this question as well: https://stackoverflow.com/questions/13875786/pointers-to-members-representations – Florian Winter Jul 26 '17 at 17:50
  • I clarified the question; I hope I didn't hijack it to an unrelated topic. – anatolyg Jul 26 '17 at 17:51

4 Answers4

9

A pointer to a class member differs from a regular pointer in that it by itself doesn't actually point at a single location in memory. For example, if you have this setup:

struct MyStruct {
    int x;
    int y;
};

int MyStruct::* ptr = &MyStruct::y;

Then the pointer ptr isn't actually pointing to a memory address because there is no one object MyStruct::y. Rather, each instance of MyStruct has its own copy of the data member y.

The C++ standard doesn't mandate how pointers-to-member are actually implemented, but a common strategy is to have the pointer-to-member store an offset in bytes from the base of the object to the field in question. That way, when you write something like

MyStruct ms;
ms.*ptr = 137;

The compiler can generate code that says "go to the base address of ms, skip forward a number of bytes specified by the value stored in ptr, then write 137."

templatetypedef
  • 362,284
  • 104
  • 897
  • 1,065
3

Pointers do not have to contain addresses. Pointers are tools to access a certain object indirectly - i.e. write code which would access an object which is unknown at compile time. Example:

a = 10; // It is known at compile time, 10 is written to object a
*pi = 10; // It is not known at compile time where 10 is written to

For normal objects, having address in the pointer is a cheapest way to achieve this goal (however, it won't be the case for C++ script!).

For members, though, normal address wouldn't work - there is no such thing as an address of a member of the class! You can only know the physical address of the member when you have a class object.

So, you have to use some sort of offset, which you than can translate to physical address once the actual object is known.

SergeyA
  • 61,605
  • 5
  • 78
  • 137
  • Can you name a modern architecture where pointer != address, *except* for pointer-to-members? – zneak Jul 26 '17 at 17:53
  • 2
    @zneak: All of them that have a memory management unit. A pointer contains a page identifier and an offset. The page identifier gets mapped by the MMU to an actual physical address, and the mapping often depends on other CPU registers so that different "processes" can each have unique mappings. For convenience, we refer to this (packed page identifier plus offset) as a "virtual address". – Ben Voigt Jul 26 '17 at 17:56
  • @BenVoigt, I'm talking about the C++ definition of a pointer vs. the assembly definition of an address. – zneak Jul 26 '17 at 17:59
  • @zneak: And then there are also "based" pointers, and cross-device pointers (for example used with CUDA), where the stored value has no meaning if passed to an instruction that expects an address. – Ben Voigt Jul 26 '17 at 18:00
  • @BenVoigt, I don't think that any of these can work with unadulterated C++. – zneak Jul 26 '17 at 18:01
  • @zneak, I just said - any C++ script. – SergeyA Jul 26 '17 at 18:02
  • @SergeyA, I've never heard of C++ scripts. I can find a handful of implementations, but they all compile to machine code. I don't think that you could reasonably implement C++, especially with regards to memory aliasing, in a way that a data pointer is not some form of address. – zneak Jul 26 '17 at 18:39
  • 1
    What I wanted to get to is that saying "you should be mindful that a C++ pointer is not necessarily a machine address" is throwing shade on an association that is largely correct. I find it much more useful and easy to teach that pointers-to-members co-opt the "pointer" name without having much to do with them, than to teach that pointers were never what you thought they were. – zneak Jul 26 '17 at 18:46
3

Pointers-to-members are not pointers.

The C++ type system contains several kinds of compound types, and there are two separate, sibling kinds of compound types that are not related to one another, despite having similar sounding names: Pointers, and "pointers to non-static class members". I'll call the latter "pointer-to-members", with hyphen, to stress that those are not a special kind of pointer, but really something entirely separate.

By the way, the type trait library separates the two concepts via std::is_pointer and std::is_member_pointer.

The two kinds of types serve entirely distinct purposes:

  • A pointer can represent the address of an object (or function) (or be null). That is, given a dereferenceable pointer, there is an actual concrete thing there that it's pointing at.

  • A pointer-to-member represents an abstract reference from a class to a non-static class member. Note that there are no objects involved. Such a pointer value does not point at anything concrete, and it has no concept of "dereferencing".

To repeat the final sentence: A pointer-to-member cannot be dereferenced, and it is not in any sense the address of an object. Rather, a pointer-to-member (specifically, to data member) can be applied to an object instance of its class, and together with the object it selects the subobject of that object corresponding to the class member that it represents. (Pointers-to-member-function have a slightly different notion of being applied to an instance; the result of the application is a function call.)

Returning to your question at last: A pointer holds an address of an object or function because it points at an object or function. A pointer-to-member does not hold an address, because it doesn't point at anything; it represents a relationship.

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
1

In C++ class members are closely related to their respective class. Thus, a declaration of a pointer to member always contains the class it belongs to. If this results in an offset into the class instance stored in the pointer or something else is not specified.

That way the C++ standard supports nearly any memory addressing scheme like, for example, the non-linear page::offset addresses of early x86, where you had to distinguish between near and far pointers for better performance.

A different case are static class members. They are like global functions/variables in the namespace of the class, eventually with protected or private access restrictions. You may retrieve pointers to static elements and use them like regular pointers.

bjhend
  • 1,538
  • 11
  • 25
  • "meaning they are not regular functions/variables with an extra object parameter" Yes, they are! https://godbolt.org/z/QPYJZE I don't know if it is enforced by the standard but this is how most implementations does it. Pointers to members are special not because how methods work but to account for inheritance, especially multiple inheritance. – Piotr Siupa Apr 29 '20 at 17:14
  • Of course, the compiler finally resolves any pointer-to-member to a memory address, because that's the purpose of any pointers. However, on C++ level pointers-to-members are different from regular pointers in the sense that you cannot use them like normal pointers. I assume this gives the compiler makers more freedom in implementing pointer-to-members, although not every compiler may use that freedom. C++ is intended to support any type of memory organization, not only the linear addressing of today's x86. – bjhend May 07 '20 at 13:49
  • Hmm, I know where my confusion came from. I actually think what you've written here is correct when it comes to member variables. However, member functions are different. They are basically normal functions with an additional parameter. (I know that OP asked about member variables.) You put functions and variables into a single basket but they are not that similar. I don't think pointers to these things are created in the same way. I'm gonna do some research. – Piotr Siupa May 07 '20 at 15:17
  • It turns out that pointer to non-static member functions are a department of quantum physics. I think they can be optimized to be like normal pointer to functions in simpler cases but when virtuality comes into view, they go absolutely crazy; total implementation defined mess. So, I think you answer is correct, except the first paragraph. Objections from my first comment are still valid. Pointers to members are a madhouse but implementation of members themselves is pretty simple. – Piotr Siupa May 07 '20 at 15:40
  • @NO_NAME I've removed the maybe too generalized first paragraph and added an example of a weird addressing scheme to exemplify it better. – bjhend May 16 '20 at 18:16