Topic: std::copy on 3 nulls - degeneracy of nullptr/zero-pointer
Author: "peter miller" <fuchsia.groan@virgin.net>
Date: Mon, 21 Feb 2011 13:39:56 CST Raw View
On Mon, 14 Feb 2011 10:32:51 -0000, Bjarke Hammersholt Roune
<bjarke.roune@gmail.com> wrote:
>
> MS VC++ 2010 is giving me assertion failures in debug mode when I run
> code like:
>
> int* p = 0;
> std::copy (p, p, p)
>
> It complains about there being a null pointer. I think that this is
> fine - it does not matter that the address can't be written to since
> the range is empty so I'm not asking for the range to be written to.
I think the problem here is the confusion between
(void*)0 and nullptr. Consider, for a moment, a processor
where main memory is a simple array:
char main_memory[ 1 << ( CHAR_BIT * sizeof( void* ) ) ];
On this system pointers are isomorphic to the integers, so
for all
size_t n;
where n < sizeof( main_memory ) it's true that
&main_memory[ n ] == (void*)n;
Since main_memory[0] is a valid address, *(char*)0 should be
dereferenceable. (AFAIK this is true on the x86, provided
memory is mapped there; it certainly was in real mode.)
On such a machine it's entirely reasonable to code
std::copy( my_interrupt_vector_table.begin()
, my_interrupt_vector_table.end()
, (interrupt_vector*)0 );
or
std::copy( (interrupt_vector*)0, (interrupt_vector*)256
, std::back_inserter( my_interrupt_vector_table ) );
So why not std::copy<char*,char*>( 0, 0, 0 )?
Back in the days of 8-bit micros, none of us blinked about 0
being the first usable address.
/Were/ std::copy<char*,char*>( 0, 0, 0) to be illegal, then
there'd be a fictitious black-hole in the address space:
char* p = (char*)( sizeof( main_memory ) - 1 );
std::copy( p, p, p ); // perfectly legal.
++p; // p wraps to zero,
std::copy( p, p, p ); // oops suddenly illegal
++p // p = (char*)1
std::copy( p, p, p ); // legal again! whohayyy!
Of course
std::copy<char*,char*>( nullptr, nullptr, nullptr );
*should* be illegal.
In general, the C++ concept of a "pointer to type T" is NOT
isomorphic to the integers, but to boost::optional<size_t>
The null pointer is the singular, undereferenceable
boost::optional<size_t>() whereas the zero pointer is the
perfectly dereferenceable boost::optional<size_t>( 0 ) and
should be a valid iterator. Historically we've fudged the
issue, by allowing the integer 0 to represent both (4.10/1).
That degeneracy is the source of this problem.
Just my $0.02.
Peter
--
Using Opera's revolutionary e-mail client: http://www.opera.com/mail/
[ comp.std.c++ is moderated. To submit articles, try posting with your ]
[ newsreader. If that fails, use mailto:std-cpp-submit@vandevoorde.com ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: "Martin B." <0xCDCDCDCD@gmx.at>
Date: Tue, 22 Feb 2011 10:57:59 CST Raw View
On 21.02.2011 20:39, peter miller wrote:
>
> On Mon, 14 Feb 2011 10:32:51 -0000, Bjarke Hammersholt Roune
> <bjarke.roune@gmail.com> wrote:
>
>>
>> MS VC++ 2010 is giving me assertion failures in debug mode when I run
>> code like:
>>
>> int* p = 0;
>> std::copy (p, p, p)
>>
> .....
>
> Of course
>
> std::copy<char*,char*>( nullptr, nullptr, nullptr );
>
> *should* be illegal.
>
> In general, the C++ concept of a "pointer to type T" is NOT
> isomorphic to the integers, but to boost::optional<size_t>
> The null pointer is the singular, undereferenceable
> boost::optional<size_t>() whereas the zero pointer is the
> perfectly dereferenceable boost::optional<size_t>( 0 ) and
> should be a valid iterator.
But note that the (vague) way the standard uses the term 'singular',
it does appear that a nullptr is *not* singular as it seems implied
that you cannot even compare a singular value to another and you can
do so with a nullptr.
cheers,
Martin
--
[ comp.std.c++ is moderated. To submit articles, try posting with your ]
[ newsreader. If that fails, use mailto:std-cpp-submit@vandevoorde.com ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]