views:

440

answers:

6

Ah-hoi, hoi,

I'm wondering if it's ok to do something like the following:

class SomeClass
{
   int bar;
};

SomeClass* foo = new SomeClass();
int offset = &(foo->bar) - foo;

SomeClass* another = new SomeClass();
*(another+offset) = 3; // try to set bar to 3

Just Curious, Dan O

A: 

It's okay (usually you'd define a macro for it like the Windows DDK's CONTAINING_RECORD macro), but I'd question why you'd need this in C++; usually you use these types of tricks in C.

Paul Betts
+1  A: 

There's nothing wrong with it, but it's very dangerous if you're not careful.

On the other hand, your code is wrong. What's the pointer type of (another+offset)? It's actually a pointer to SomeClass, not an int, so you should at least cast the pointer to (int *):

 *((int *)(another + offset)) = 3;

The offset is another thing to watch out for, because it's always in units of the type the pointer points to. In short, when int is 4 bytes long, adding 1 to a (int *) pointer will actually add 4 to it, so it's better to cast any pointer to (char *) before doing calculations.

So for your example:

SomeClass* foo = new SomeClass();
int offset = (char *)&(foo->bar) - (char *)foo;

SomeClass* another = new SomeClass();
*((int *)((char *)another+offset)) = 3; // try to set bar to 3
Philippe Leybaert
A: 

Looking at the raw addresses, that seems like it would work, but for starters in your statement: int offset = &(foo->bar) - foo; You are trying to substract different pointer types. So if you reniterpret_cast them to char * it should give you what you are looking for.

Although this seems too convoluted and error-prone to be any useful.

Ramon Zarazua
+10  A: 

I suppose tecnically it might work out.

However, there are several problems. bar is private. You are mixing pointers of different types (pointer arithmetic relies on the pointer type: int* + 1 and char* + 1 have different results because int and char have a different size).

Have you also considered pointers to members:

#include <cassert>

struct SomeClass
{
   int bar;
};

int main() {
    int SomeClass::*mem_ptr = &SomeClass::bar;
    SomeClass foo;
    foo.*mem_ptr = 3;
    assert(foo.bar == 3);
}
UncleBens
+1 beat me to it.
Steve Jessop
+1 Pointer-to-member seems to be what the original questioner was looking for.
GBegen
Pointer to member is very interesting, I don't think it would allow me to implement the design I'm thinking about (but that's beside the point, this is a good answer to the question I asked).
Dan O
The only documentation I've found on pointers to members refers to them as pointers to member functions, taking the address of a member variable is novel.Either way I should be able to cache a pointer to a member function or a variable and get the functionality I desire.Thanks! (still looking for more docs, by the way, just reading the faq right now).
Dan O
+4  A: 

The idea is OK for POD classes (same things other people have said about the errors in your example code). For non-POD classes, you cannot necessarily identify a member just by an offset from the object pointer. Consider for example if the member is part of a base class, or equivalently if you want to apply the offset to a pointer to a derived class, but there is multiple- or virtual inheritance involved.

However, are you aware of pointers-to-member?

struct SomeClass
{
    int bar;
};

// fieldtoset is a pointer-to-member
int SomeClass::*fieldtoset = &SomeClass::bar;

SomeClass* another = new SomeClass();
// syntax works as if "*fieldtoset" is "bar" (the member variable referand)
another->*fieldtoset = 3 // set bar to 3
Steve Jessop
+1 Pointer-to-member seems to be what the original questioner was looking for.
GBegen
The pointer to member stuff is interesting, but probably wouldn't work for what I'm trying to do, ultimately I think I'll use a single object to write my values into and copy it when I'm done.
Dan O
+1  A: 

What you're doing in your example is not a good use of pointers. It may not work if the compiler does things differently than you expect, and it can be done just as simply, just as efficiently, and with less source code, using normal methods.

There's nothing wrong with pointer arithmetic if you have a valid use. There aren't very many not already covered by the language though.

Jay