const char* vs char const*

E

engineer

Hi,

Can someone give me an easy explanation as well as the difference between the following three statements.

const char* p
char const* m
char* const n

thanks
-Ahmed
 
Ö

Öö Tiib

Can someone give me an easy explanation as well as the difference between
the following three statements.

const char* p
char const* m
char* const n

There are no difference between type of 'p' and 'm'. Both are mutable
pointers to immutable char. 'n' is immutable pointer to mutable char.
 
G

Gerhard Fiedler

Öö Tiib said:
There are no difference between type of 'p' and 'm'. Both are mutable
pointers to immutable char. 'n' is immutable pointer to mutable char.

In addition to what Öö wrote: Try to read the type declaration from
right to left, "translating" * with "pointer to", "const" with
"immutable" and considering that an "immutable char" is the same (in
this context) as a "char immutable".

Gerhard
 
J

James Kanze

Can someone give me an easy explanation as well as the
difference between the following three statements.
const char* p
char const* m
char* const n

Just apply the general rule: const applies to whatever is
immediately to the left of it. If nothing is to the immediate
left of it, move it to the right until there is something.
Thus:

const char* p; // The same as char const* p (which would be preferable)
char const* m; // (non-const) pointer to const char.
char *const n; // Const pointer to (non-const) char.
char const* const* o; // Const pointer to const char.

In an ideal world, you'd never see the first declaration you
give, as it leads to a great deal of confusion when typedefs are
involved:

typedef char* CPtr;
CPtr const p1; // char *const p1
const CPtr p2; // char *const p2 !!!
 
J

Jorgen Grahn

Just apply the general rule: const applies to whatever is
immediately to the left of it. If nothing is to the immediate
left of it, move it to the right until there is something.
Thus:

const char* p; // The same as char const* p (which would be preferable)
char const* m; // (non-const) pointer to const char.
char *const n; // Const pointer to (non-const) char.
char const* const* o; // Const pointer to const char.

In an ideal world, you'd never see the first declaration you
give, as it leads to a great deal of confusion when typedefs are
involved:

typedef char* CPtr;
CPtr const p1; // char *const p1
const CPtr p2; // char *const p2 !!!

I think you're wrong here -- the const cannot "invade" the typedef, so
both p1 and p2 are constant pointers to non-const stuff, like you'd
expect.

Of course, many would say that in ideal world you don't see a lot of
typedef:ed pointers either. They are a source of confusion too.

/Jorgen
 
Ö

Öö Tiib

Of course, many would say that in ideal world you don't see a lot of
typedef:ed pointers either. They are a source of confusion too.

Can you describe the situation where those many would say that?

For example: All C++ standard library containers (and some non-containers)
have 'pointer' and 'const_pointer' member typedefs. Some non-containers
have such typedefs as well. Some people ignore these, some use.
Lack of such typedefs (in a weakly made custom container) may cause
inconvenience for people who expect such typedefs ... but what confusion?
 
J

James Kanze

I think you're wrong here -- the const cannot "invade" the typedef, so
both p1 and p2 are constant pointers to non-const stuff, like you'd
expect.

That's what I said, no?
Of course, many would say that in ideal world you don't see a lot of
typedef:ed pointers either. They are a source of confusion too.

I'm tempted to say "wishful thinking". I agree that typedef'ing
pointers is bad policy. But the same problems occur in more
complicated cases, where people are typedef'ing pointers to
member functions, or whatever. (Of course, I would argue that
even then, typedef's cause confusion. But given the syntax,
people do want to do it.)
 
J

James Kanze

Can you describe the situation where those many would say that?
For example: All C++ standard library containers (and some non-containers)
have 'pointer' and 'const_pointer' member typedefs. Some non-containers
have such typedefs as well. Some people ignore these, some use.
Lack of such typedefs (in a weakly made custom container) may cause
inconvenience for people who expect such typedefs ... but what confusion?

The situation is a bit different there. 'pointer' and
'const_pointer' are *not* necessarily T* and T const*. And the
typedef's are really only for use in template functions; you'd
never use them in cases where you knew the real type.
 
Ö

Öö Tiib

The situation is a bit different there. 'pointer' and
'const_pointer' are *not* necessarily T* and T const*.

It is guaranteed to be something that works like pointer. It on most cases
And the typedef's are really only for use in template functions;
you'd never use them in cases where you knew the real type.

It does not always matter that you know the real type. For example
'Names' are typedefed 'std::vector<Name>'. Then it happens that you
need a pointer 'n' to element of 'Names' for whatever reason. The
purpose is cleaner (and maintenance easier) if you declare it as
'Names::pointer' instead of 'Name*' despite you know that these
are very same type.
 
J

James Kanze

It is guaranteed to be something that works like pointer. It on most cases
is actually pointer (besides vector<bool> and when using some fancy
allocator).

The whole point of having the pointer typedef is that it may not
be a pointer. Or it may be some special type of pointer: all of
these typedef's were introduced to support things like __huge
(or whatever it was) on architectures where pointers could be
declared to have different sizes. Without allocators, the
typedef wouldn't be there.
It does not always matter that you know the real type. For example
'Names' are typedefed 'std::vector<Name>'. Then it happens that you
need a pointer 'n' to element of 'Names' for whatever reason. The
purpose is cleaner (and maintenance easier) if you declare it as
'Names::pointer' instead of 'Name*' despite you know that these
are very same type.

The code is considerably more readable if you use Name*, rather
than Names::pointer (and if you use std::vector<Name>, rather
than Names). Maintainable is a point of view: using Names
and Names::pointer has the advantage of not requiring any other
changes (hopefully) if you do later change to use a custom
allocator. Otherwise, it's just obfuscation.
 
Ö

Öö Tiib

The code is considerably more readable if you use Name*, rather
than Names::pointer (and if you use std::vector<Name>, rather
than Names). Maintainable is a point of view: using Names
and Names::pointer has the advantage of not requiring any other
changes (hopefully) if you do later change to use a custom
allocator. Otherwise, it's just obfuscation.

The bloat that results when using some relatively well performing
container without typedefs is too lot for my simple mind. Consider:

boost::intrusive::multiset< Thing, boost::intrusive::member_hook<Thing, boost::intrusive::set_member_hook<>, &Thing::member_hook_> > things;

For me it is hard like that to use that type and to read code that
uses that type. IOW we better remain on different opinions here.
Readability depends on reader. Different readers have different
capabilities.
 
J

Jorgen Grahn

That's what I said, no?

Oops, sorry! Yes, you did. I saw a claim that wasn't there, namely
that 'const CPtr' and 'CPtr const' would be different things.

I think my misunderstanding was 70% sloppy reading and 30% not being
prepared for the claim that the actual behavior is confusing.
(Although it would be if you mentally expand CPtr to "char *".)
I'm tempted to say "wishful thinking".

Yes, that's what "ideal world" means. But they are actually quite rare
in the code I work with. There may be other ecosystems where they are
common though.

/Jorgen
 
J

Jorgen Grahn

Disagree ...

If you're thinking of 'typedef unsigned TcpPort;' and such, I prefer
to create small wrapper classes. The typedef gives you a meaningful
name; the class also gives you type safety ('port = date + 1' won't
compile unless you tell it to).
The _only_ time typedef should be used in C++ code is when a C-type
function pointer "type" is required.

Disagree ...
They should never be used with
structs (e.g. typedef struct {} xx_t;), since struct names are equiv to typedef
in C++. Likewise with enum.

If you're using a pointer, don't hide the declaration in a macro or typedef;
why make the maintenance programmer go lookup what the typedef is?

Agreed. But these are examples of typedef in C-like scenarios only.
Typedef is important in classes and templates.

/Jorgen
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,012
Latest member
RoxanneDzm

Latest Threads

Top