Re: Transitioning libgomp from C to C++ implementation

Christopher Bazley via Gcc <[email protected]>
Newsgroups gmane.comp.gcc.devel
Organization Arm
Message-ID <[email protected]>
On 09/05/2026 14:21, Jonathan Wakely wrote:
> 
> 
> On Sat, 9 May 2026, 09:40 Christopher Bazley via Gcc, <[email protected] 
> <mailto:[email protected]>> wrote:
> 
> 
> 
>     This flaw in the design of C++ is also what necessitated the invention
>     of nullptr, which would otherwise be unnecessary. Had the purpose of
>     'void *' not been misunderstood, nullptr could simply have been defined
>     as a macro: ((void *)0).
> 
> 
> No it couldn't.

Yes, my words misrepresented the order of events.

It is surprising to me that nullptr wasn't invented until C++11, given 
that there were known issues with overloading since the inception of C 
with classes. Those early problems with overloading do appear to stem 
from Stroustrup's redefinition of the semantics of the 'void *' type. I 
stand by that.

The idea of using '0' as a null pointer constant seems so bad to me that 
I can scarcely believe it was standard C++ for so long. That is what led 
to my wrong statement.

> This thread is getting more and more of topic, but defining nullptr as 
> just a void* would not allow the useful property of overloading 
> functions like unique_ptr::operator= on whether the argument is an 
> actual pointer (which would replace the owned pointer, but is disallowed 
> by plain assignment) or is the special nullptr value (which is allowed).
> 
> That is:
> 
> uptr = (void*)0; // error
> uptr = nullptr; // ok

Thanks for the explanation.

I can see that nullptr has some use for template type deduction, 
although based on your description I find that usage questionable. 
Assignments do not generally have different semantics depending on 
whether the assigned expression is a literal or not.

> I think you have an overly simplistic idea of why nullptr was added to 
> C++, leading to an incorrect conclusion about it only being necessary 
> because of C++ pointer conversion rules.

My "overly simplistic idea" was derived from my reading of Stroustrup 
(1994, reprinted 1998), 'The Design and Evolution of C++' (pp 230):

================
A void* cannot be assigned to anything without a cast.  Allowing 
implicit conversions of void* to other pointer types would open a 
serious hole in the type sustem.  One might make a special case for 
(void*)0, but special cases should only be admitted in dire need.  Also, 
C++ usage was determined long before there was an ANSI C standard, and I 
do not want to have any critical part of C++ rely on a macro. 
Consequently, I used plain 0, and that has worked very well over the 
years.  People who insist on a symbolic constant usually defined one of

const int NULL = 0; // or
#define NULL 0

As far as the compiler is concerned, NULL and 0 are then synonymous. 
Unfortunately, so many people have added definitions NULL, NIL, Null, 
null, etc. to their code that providing yet another definition can be 
hazardous.

There is one kind of mistake that is not caught when 0 (however spelled) 
is used for the null pointer.  Consider:

void f(char*);

void g() { f(0); } // calls f(char*)

Now add another f() and the meaning of g() silently changes:

void f(char*);
void f(int);

void g() { f(0); } // calls f(int)

This is an unfortunately side effect of 0 being an int that can be 
promoted to the null pointer, rather than a direct specification of the 
null pointer.  I think a good compiler should warn, but I didn't think 
of that in time for CFront.  Making the call to f(0) ambiguous rather 
than resolving it in favour of f(int) would be feasible, but would 
probably not satisfy the people would want NULL or nil to be magical.
================

What I remembered was Stroustrup's explanation (which I don't find 
particularly compelling) of why C++ did not use (void*)0 as a null 
pointer constant. However, I forgot that his book can't be used directly 
to justify the invention of nullptr, because nullptr hadn't been 
invented when he wrote the book.

> It exists for reasons related to template type deduction and 
> overloading, not because void* isn't convertible to other pointer types.

I don't think nullptr is necessary to resolve the problem with 
overloading that Stroustrup mentioned in his book. Consider his example, 
assuming that NULL is defined as ((void *)0) and assuming that C++ had 
not departed from C's semantics for void *:

void f(char*);

void g() { f(NULL); } // calls f(char*)

But also:

void f(char*);
void f(int);

void g() { f(NULL); } // still calls f(char*)

-- 
Christopher Bazley
Staff Software Engineer, GNU Tools Team.
Arm Ltd, 110 Fulbourn Road, Cambridge, CB1 9NJ, UK.
http://www.arm.com/
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.