views:

245

answers:

6

In my program, I have objects (of the same class) that must all have a unique identifier. For simplicity and performance, I chose to use the address of the object as identifier. And to keep the types simple, I use (void*) as a type for this identifier. In the end I have code like this:

class MyClass {
public:
  typedef void* identity_t;
  identity_t id() const { return (void*)this; }
}

This seems to be working fine, but gcc gives me a strict-aliasing warning. I understand the code would be bad if the id was used for data transfer. Luckily it is not, but the question remains: will aliasing optimisations have an impact on the code produced? And how to avoid the warning?

Note: I am reluctant to use (char*) as this would imply the user can use the data for copy, which it can not!

+2  A: 

Try using

return static_cast<void*>(this);

This should be perfectly safe, any pointer should be able to be cast to void * without risk of loss.

I originally suggested dynamic_cast(this);, but after reading up a bit I think it adds no advantage, and since it's RTTI-only it's not a good solution in general.

By the way, I would make the returned value const, since the identity of an object cannot change.

unwind
What advantage does using `dynamic_cast` instead of plain simple `static_cast` have in this case?
avakar
none. But some people think it's magic
jalf
The difference is that the dynamic cast will result in a pointer to the most derived class of `this`, whereas the C-style cast will just reinterpret `this` as void*. I'm not sure whether that's an advantage or not. Btw, you can't dynamic_cast to void* in the example in the question, because MyClass is not a polymorphic type.
Steve Jessop
@avakar: None, it seems. I changed it so my second suggestion, which was static_cast<>(), became the primary. :)
unwind
A: 

Why not using type MyClass *?

Or type intptr_t?

Didier Trosset
intptr_t didn't exist in C++ last I checked. And I assume the ID's have to be comparable between different classes, so `MyClass*` wouldn't work either.
jalf
+4  A: 

You could try using the type uintptr_t instead of void*. uintptr_t is a integer type that is defined as being big enough to hold any pointer value. And since it's not actually a pointer, the compiler won't flag any aliasing problems.

class MyClass {
public:
    typedef uintptr_t identity_t;
    identity_t id() const { return (identity_t)this; }
}
Zach Hirsch
There is no `uintptr_t` in C++. It's C99 (and possibly C++0x).
avakar
Surprisingly, using `uintptr_t` leads to the following warning:warning: dereferencing pointer ‘__x.939’ does break strict-aliasing rules
PierreBdR
@Zach: your code keeps the logical constness violation error.
fnieto
@avakar True, but g++ seems to handle the type just fine :)
Zach Hirsch
@PierreBdR I'm not getting that warning when I compile this code. Maybe you're getting the error somewhere else in your program (are you casting the uintptr_t back to a MyClass*)?
Zach Hirsch
@fnieto What advantage does static_cast give in this case, other than purity? Can you give an example of using static_cast to cast const MyClass *const to uintptr_t?
Zach Hirsch
@Zach: the advantage is that it is a C++ cast. The tag of the question es C++, not mixed C/C++. Same apply to avakar advise, in spite your C++ compiler executes with C support by default.
fnieto
+1  A: 

I can't see any aliasing issues. However, you are casting away constness (since the id function is const), which the compiler might be unhappy about. Perhaps it'd be better to use const void* as your ID type.

Alternatively, cast the address to an integer type such as size_t. Then it is no longer a pointer, and aliasing becomes a non-issue.

jalf
+3  A: 

You are violating logical constness returning the object as mutable in a const method.
As Neil points out, no cast is needed.

class MyClass {
public:
  typedef const void* identity_t;
  identity_t id() const { return this; }
};
fnieto
A: 

I suggest using a long int with a random value (remember to seed the generator correctly before using). The object's addresses will not be unique if you serialize the object.

Thomas Matthews