Home » C++ » Is it a good idea to typedef pointers?

Is it a good idea to typedef pointers?

Posted by: admin November 30, 2017 Leave a comment

Questions:

I looked through some code and noticed that the convention was to turn pointer types like

SomeStruct* 

into

typedef SomeStruct* pSomeStruct;

Is there any merit to this?

Answers:

This can be appropriate when the pointer itself can be regarded as a “black box”, that is, a piece of data whose internal representation should be irrelevant to the code.

Essentially, if your code will never dereference the pointer, and you just pass it around API functions (sometimes by reference), then not only does the typedef reduce the number of *s in your code, but also suggests to the programmer that the pointer shouldn’t really be meddled with.

This also makes it easier to change the API in the future if the need arises, for instance using an ID rather than a pointer (or vice versa). Since the pointer was never supposed to be dereferenced in the first place, existing code won’t break.

Questions:
Answers:

Not in my experience. Hiding the ‘*‘ makes the code hard to read.

Questions:
Answers:

The only time I use a pointer inside the typedef is when dealing with pointers to functions:

typedef void (*SigCatcher(int, void (*)(int)))(int);

typedef void (*SigCatcher)(int);

SigCatcher old = signal(SIGINT, SIG_IGN);

Otherwise, I find them more confusing than helpful.



The struck-out declaration is the correct type for a pointer to the signal() function, not of the signal catcher. It could be made clearer (using the corrected SigCatcher type above) by writing:

 typedef SigCatcher (*SignalFunction)(int, SigCatcher);

Or, to declare the signal() function:

 extern SigCatcher signal(int, SigCatcher);

That is, a SignalFunction is a pointer to a function which takes two arguments (an int and a SigCatcher) and returns a SigCatcher. And signal() itself is a function which takes two arguments (an int and a SigCatcher) and returns a SigCatcher.

Questions:
Answers:

This can help you avoid some errors. For example in following code:

int* pointer1, pointer2;

pointer2 is not an int *, it is simple int.
But with typedefs this is not gonna happen:

typedef int* pInt;
pInt pointer1, pointer2;

They are both int * now.

Questions:
Answers:

It (like so many answers) depends.

In C this is very common as you are trying to disguise that an object is a pointer. You are trying to imply that this is the object that all your functions manipulate (we know it is a pointer underneath but it represents the object you are manipulating).

MYDB   db = MYDBcreateDB("Plop://djdjdjjdjd");

MYDBDoSomthingWithDB(db,5,6,7);
CallLocalFuc(db); // if db is not a pointer things could be complicated.
MYDBdestroyDB(db);

Underneath MYDB is probably a pointer at some object.

In C++ this is no longer required.
Mainly because we can pass things around by reference and the methods are incorporated into the class declaration.

MyDB   db("Plop://djdjdjjdjd");

db.DoSomthingWithDB(5,6,7);
CallLocalFuc(db);   // This time we can call be reference.
db.destroyDB();     // Or let the destructor handle it.

Questions:
Answers:

This is a matter of style. You see this kind of code very frequently in the Windows header files. Though they tend to prefer the all upper case version instead of prefixing with a lower case p.

Personally I avoid this use of typedef. It’s much clearer to have the user explicitly say they want a Foo* than PFoo. Typedef’s are best suited these days for making STL readable 🙂

typedef stl::map<stl::wstring,CAdapt<CComPtr<IFoo>> NameToFooMap;

Questions:
Answers:

Typedef is used to make code more readable, but making pointer as typedef will increase confusion. Better to avoid typedef pointers.

Questions:
Answers:

If you do this, you will be unable to create STL containers of const pSomeStruct since the compiler reads:

list<const pSomeStruct> structs;

as

list<SomeStruct * const> structs;

which is not a legal STL container since the elements are not assignable.

See this question .

Questions:
Answers:

Win32 API does this with just about every structure (if not all)

POINT => *LPPOINT
WNDCLASSEX => *LPWNDCLASSEX
RECT => *LPRECT
PRINT_INFO_2 => *LPPRINT_INFO_2

It’s nice how it is consistent, but in my opinion it doesn’t add any elegance.

Questions:
Answers:

Discussion pitched assuming the language of interest is C. Ramifications for C++ have not been considered.

Using a a pointer typedef for an untagged structure

The question Size of a struct that is defined as a pointer raises an interesting side-light on using typedef for (structure) pointers.

Consider the tagless concrete (not opaque) structure type definition:

typedef struct { int field1; double field2; } *Information;

The details of the members are completely tangential to this discussion; all that matters is that this not an opaque type like typedef struct tag *tag; (and you can’t define such opaque types via a typedef without a tag).

The question raised is ‘how can you find the size of that structure’?

The short answer is ‘only via a variable of the type’. There is no tag to use with sizeof(struct tag). You can’t usefully write sizeof(*Information), for example, and sizeof(Information *) is the size of a pointer to the pointer type, not the size of the structure type.

In fact, if you want to allocate such a structure, you can’t create one except via dynamic allocation (or surrogate techniques that mimic dynamic allocation). There is no way to create a local variable of the structure type whose pointers are called Information, nor is there a way to create a file scope (global or static) variable of the structure type, nor is there a way to embed such a structure (as opposed to a pointer to such a structure) into another structure or union type.

You can — must — write:

Information info = malloc(sizeof(*info));

Apart from the fact that the pointer is hidden in the typedef, this is good practice — if the type of info changes, the size allocation will remain accurate. But in this case, it is also the only way to get the size of the structure and to allocate the structure. And there’s no other way to create an instance of the structure.

Is this harmful?

It depends on your goals.

This isn’t an opaque type — the details of the structure must be defined when the pointer type is typedef‘d.

It is a type that can only be used with dynamic memory allocation.

It is a type that is nameless. The pointer to the structure type has a name, but the structure type itself does not.

If you want to enforce dynamic allocation, this seems to be a way to do it.

On the whole, though, it is more likely to cause confusion and angst than enlightenment.

Summary

It is, in general, a bad idea to use typedef to define a pointer to a tagless stucture type.

Questions:
Answers:

My answer is a clear “No”.

Why?

Well, first of all, you simply exchange a single character * for another single character p. That is zero gain. This alone should keep you from doing this as it is always bad to do extra stuff that’s pointless.

Second, and that is the important reason, the * carries meaning that is not good to hide. If I pass something to a function like this

void foo(SomeType bar);

void baz() {
    SomeType myBar = getSomeType();
    foo(myBar);
}

I do not expect the meaning of myBar to be changed by passing it to foo(). After all, I’m passing by value, so foo() only ever sees a copy of myBar right? Not when SomeType is aliased to mean some kind of pointer!

This applies both to C pointers and C++ smart pointers: If you hide the fact that they are pointers to your users, you will create confusion that is totally unnecessary. So, please, don’t alias your pointers.

(I believe the habit of typedefing pointer types is just a misguided attempt to hide how many stars one has as a programmer http://wiki.c2.com/?ThreeStarProgrammer .)

Questions:
Answers:

Some time ago, i’d have answered “no” to this question. Now, with the rise of smart pointers, pointers are not always defined with a star ‘*’ anymore. So there is nothing obvious about a type being a pointer or not.

So now i’d say : it is fine to typedef pointers, as long as it is made very clear that it is a “pointer type”. That means you have to use a prefix/suffix specifically for it. No, “p” is not a sufficient prefix, for instance. I’d probably go with “ptr”.

Questions:
Answers:

The purpose with typedef is to hide the implementation details, but typedef-ing the pointer property hides too much and makes the code harder to read/understand.
So please do not do that.


If you want to hide implementation details (which often is a good thing to do), do not hide the pointer part. Take for instance at the prototype for the standard FILE interface:

FILE *fopen(const char *filename, const char *mode);
char *fgets(char *s, int size, FILE *stream);

here fopen returns a pointer to some structure FILE (which you do not know the implementation details for). Maybe FILE is not such a good example because in this case it could have worked with some pFILE type that hid the fact that it is a pointer.

pFILE fopen(const char *filename, const char *mode);
char *fgets(char *s, int size, pFILE stream);

However, that would only work because you never mess around with the content that is pointed to directly. The moment you typedef some pointer that you some places modify the code becomes very hard to read in my experience.