views:

219

answers:

6

What is the right way to typedef a type and the same type's pointer? Here is what I mean. Should I do this:

typedef unsigned int delay;
typedef unsigned int * delayp;

Or should I do this:

typedef unsigned int delay;
typedef delay * delayp;

Or perhaps I should not typedef pointer at all and just use delay * instead of delayp everywhere I find necessary?

Thanks, Boda Cydo.

+21  A: 

The right way is not to do it. Hiding the fact that something is a pointer is commonly seen as bad style.

anon
This. Do not typedef away a pointer.
DeadMG
Exactly. And naming the pointer type in a way that it is not clear its a pointer is evil.
PeterK
'Hiding the fact that something is a pointer is commonly seen as bad style.' Says who?
Sam
I agree that hiding pointers away might lead to confusion. But I would be ok with a `typedef delay* delay_ptr;` that does not hide the pointer nature. @Sam, it depends on the situation. In general it might lead to confusion unless you want it (that is, you are providing an opaque type as in a handler...)
David Rodríguez - dribeas
It used to be common practice in old Windows SDKs... which is not denying that it is bad style.
UncleZeiv
I've never ever seen the benefit to hiding pointers.
acron
Oh my, If I had 5 cents for every time I've seen it done. And by the way I completely agree.
C Johnson
@Sam: typedef'ing a pointer leads to inconsistencies. Namely `const delay*` and `const delayp` ( == `delay* const`) are not the same type. You can't add-in a `const` or `volatile` qualifier to a typedef'ed pointer/reference. So either you need to generate all possible variants... or simply never typedef to a pointer/reference type.
Matthieu M.
+3  A: 

typedef unsigned int delay, *delayp;

badgerr
Wow?? How does this work?
bodacydo
It works the same way `char c, *s;` works.
R..
This is very surprising because I thought typedef worked like this: `typedef (...) new_name`. So in case of pointer, I thought it was `typedef (unsigned int *) new_name`. Now it turns out it works like declaring types, so it's not `typedef (...) new_name` because in `typedef unsigned int delay, *delayp` the `(...)` part is still `(unsigned int)` but the `*` has moved near `delayp`. I am actually very confused now.
bodacydo
@bodacydo: `typedef` syntax works the same way as declaring variables.
jamesdlin
+2  A: 

Generally, you do the second block because you're re-using the type. For example, if delay needed to become an unsigned long, the definition of delayp wouldn't need to be modified.

That said, hiding pointers behind typedef's is usually a very bad idea. It's more acceptable for things that act like pointers, like iterators or smart pointers:

typedef std::vector<int> my_container;
typedef my_container::iterator my_iterator;

typedef some_type<blah> my_type;
typedef shared_ptr<my_type> my_shared_ptr;
GMan
A: 

In case of int it shouldn't make any difference, but in case of aggregate types latter approach is better, because in former case *delay isn't equivalent to delayp, and cast would be needed to use them interchangeably.

But as others mention, you better be off just with delay.

qrdl
+3  A: 

typedefing raw pointer types is pointless (ha!). It doesn't provide any real abstraction (consumers must still understand that the types are pointers, and they must figure out how to parse whatever naming convention you use for the typename to determine what the pointee type is).

It's also bad form because if you have:

typedef T* T_ptr;

Then const T* foo and const T_ptr bar are two very different things. (foo is a pointer to a const T; it's a promise not to mutate the pointee through that pointer. bar is a pointer that is itself const; it can't be changed to point to something else.)

The first case (pointer-to-const) is important: it helps to enforce function contracts.

The second case is much, much less useful.

Therefore if you were to add a typedef for a pointer type, to be useful you'd need to create two:

typedef T* T_ptr;
typedef const T* const_T_ptr;

A tolerable exception is in C++ when you have smart pointer classes. In these cases, typing boost::shared_ptr<T> might be tedious enough that creating a typedef for it is a reasonable convenience.

jamesdlin
A: 

Your second form

typedef delay * delayp;
is better because if you'll want in the future to change "delay" typedef from int to something else (long, for instance), you can make this change in one place only.

hiding pointers may be useful if you want to allow yourself (in the future) to migrate to some kind of smartpointers instead of raw pointers (Your code will remain almost the same if pointer typedef is used) Otherwise, hiding pointers is unusable.