Are references to not-quite-objects legal?

A

Alf P. Steinbach

One main usage of references is for arguments, to replace e.g. void foo(int*)
with void foo(int&).

However, our Holy Standard claims that a reference must be initialized with an
_object_, before going on to show examples of initializing with lvalues.

And there are some lvalues -- I cannot find any restrictions on dereferencing
that would forbid this -- that aren't very real objects. They're more like
hypothetical objects. So, is the program below a correct C++ program?

#include <cstddef>

void doStuff( int& firstElem, std::size_t size )
{
// whatever
for( std::size_t i = 0; i < size; ++i ) { (&firstElem); }
}

int main()
{
int grumblegrumble[666];
doStuff( *(new int[0]), 0 );
doStuff( grumblegrumble[666], 0 );
//doStuff( destroyedButNotDeallocated, 0 );
}

The reason I ask is that if it is a correct program, then in a small piece I'm
writing I'll use some special term to denote pointers that do point to fully
real objects, and corresponding references. I thought "RealGood" would be
nice for that purpose, with Un-RealGood, "URG", denoting not RealGood, where
RealGood implies valid. But if the actual arguments in this program are not
allowed by the standard, then the not-quite-objects do not, presumably, even
exist as "objects", and then it would perhaps be incorrect even to dereference
the URG pointers shown here?
 
A

Alf P. Steinbach

I accidentally posted this to comp.lang.c++, it was meant for comp.std.c++; so
now it's multi-posted, sorry.
 
B

Branimir Maksimovic

Alf P. Steinbach said:
One main usage of references is for arguments, to replace e.g. void
foo(int*)
with void foo(int&).

However, our Holy Standard claims that a reference must be initialized
with an
_object_, before going on to show examples of initializing with lvalues.

And there are some lvalues -- I cannot find any restrictions on
dereferencing
that would forbid this -- that aren't very real objects. They're more
like
hypothetical objects. So, is the program below a correct C++ program?

#include <cstddef>

void doStuff( int& firstElem, std::size_t size )
{
// whatever
for( std::size_t i = 0; i < size; ++i ) { (&firstElem); }
}


should be
template < size_t size>
void doStuff(int (&a) [size])
{
// whatever
for( std::size_t i = 0; i < size; ++i ) { a; }
}
void doStuff(int (&a) [0])
{
}
int main()
{
int grumblegrumble[666];
int empty [0] ;
doStuff(empty);
doStuff(*(int(*)[0])new int[0], 0 );
doStuff(grumblegrumble);
//doStuff( destroyedButNotDeallocated, 0 );
}
Greetings, Bane.
 
A

Andrew Koenig

And there are some lvalues -- I cannot find any restrictions on
dereferencing
that would forbid this -- that aren't very real objects. They're more
like
hypothetical objects. So, is the program below a correct C++ program?

#include <cstddef>

void doStuff( int& firstElem, std::size_t size )
{
// whatever
for( std::size_t i = 0; i < size; ++i ) { (&firstElem); }
}

int main()
{
int grumblegrumble[666];
doStuff( *(new int[0]), 0 );
doStuff( grumblegrumble[666], 0 );
//doStuff( destroyedButNotDeallocated, 0 );
}


The moment you mention grumblegrumble[666] for any reason, the behavior is
undefined. Ditto for *(new int[0]). The definition of doStuff is
irrelevant.

The point is that grumblegrumble[666] is equivalent to
*(grumblegrumble+666), and grumblegrumble+666 is an off-the-end pointer.
Dereferencing such a pointer is undefined. Analogously for *(new int[0]).
 
B

Branimir Maksimovic

void doStuff(int (&a) [size])
{
// whatever
for( std::size_t i = 0; i < size; ++i ) { a; }
}
void doStuff(int (&a) [0])
{
}
int main()
{
int grumblegrumble[666];
int empty [0] ;
doStuff(empty);
doStuff(*(int(*)[0])new int[0], 0 );


should be
doStuff(*new int[0][0]);
 
B

Branimir Maksimovic

Branimir Maksimovic said:
doStuff(*(int(*)[0])new int[0], 0 );

should be
doStuff(*new int[0][0]);

Gosh, now is clear ub, can't be done without cast,
in which case (I'm not sure but I think) is again ub
since new[] does not returns pointer to array. :(

Greetings, Bane.
 
B

Branimir Maksimovic

Branimir Maksimovic said:
Branimir Maksimovic said:
doStuff(*(int(*)[0])new int[0], 0 );

should be
doStuff(*new int[0][0]);

Gosh, now is clear ub, can't be done without cast,
in which case (I'm not sure but I think) is again ub
since new[] does not returns pointer to array. :(

doStuff(*new int[1][0]);

this can work reliably :)
 

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

No members online now.

Forum statistics

Threads
474,436
Messages
2,571,696
Members
48,796
Latest member
Greg L.
Top