reference to pointer

R

Ralf Goertz

Hi,

according to the FAQ, references can be thought of as aliases and I
sometimes used them to avoid lengthy variables. It seems to be possible
to use aliases for pointers like:

#include <iostream>

using namespace std;

int main() {
int i(42);
int* p(&i);
int &r(i);
int* &rp(p);
cout<<"int:\t"<<i<<endl;
cout<<"int*:\t"<<*p<<endl;
cout<<"int&:\t"<<r<<endl;
cout<<"int*&:\t"<<*rp<<endl;
return 0;
}

This compiles fine, but the following:

void foo(someClass* s) {
someOtherClass* &pr(reinterpret_cast<someOtherClass*>(s->ptr));
/* ... */
}

where someClass has a member char *ptr, gives an error with g++:

error: invalid initialization of non-const reference of type
‘someOtherClass*&’ from a temporary of type ‘someOtherClass*’

I can fix this by declaring 'pr' to be a reference to the dereferenced
object:

someOtherClass &pr(*reinterpret_cast<someOtherClass*>(s->ptr));

which might be the better way, anyway. But what is the problem with the
reference to the pointer? Furthermore, does the creation of the
reference lead to substantial overload? The function foo is called a
zillion times and my hope is that 'pr' is optimized away by the compiler
(using -O3). What about the reinterpret_cast, is it done during
compilation? Then I might use a macro instead of a reference.
 
J

Jonathan Lee

Hi Ralf,
void foo(someClass* s) {
        someOtherClass* &pr(reinterpret_cast<someOtherClass*>(s->ptr));
        /*  ... */

}

The result of reinterpret_cast<>() is an rvalue. It can't be
referenced, or used to initialize a reference. That's more or less
what the error message is saying.

You'd have to have another variable to store the result of the
reinterpret_cast<>(). For example,

someOtherClass* p2 = reinterpret_cast<someOtherClass*>(s->ptr);
someOtherClass* &pr(p2);

Though I don't really see the point in doing that.

Note also that reinterpret_cast<>() is pretty much an all around bad
idea. Especially for circumventing the type system, as you seem to
have done. Personally, I would have define a constructor for
someOtherClass() that accepted your char*, then create an instance of
your object and act on that. Copying it back out if need be. If your
code truly runs "a zillion" times (heh) this shouldn't be costly to
do.

--Jonathan
 
R

Ralf Goertz

Jonathan said:

Hi Jonathan,
The result of reinterpret_cast<>() is an rvalue. It can't be
referenced, or used to initialize a reference. That's more or less
what the error message is saying.

Okay.
Note also that reinterpret_cast<>() is pretty much an all around bad
idea. Especially for circumventing the type system, as you seem to
have done. Personally, I would have define a constructor for
someOtherClass() that accepted your char*, then create an instance of
your object and act on that. Copying it back out if need be. If your
code truly runs "a zillion" times (heh) this shouldn't be costly to
do.

I don't have a choice. foo() is a "User Defined Function" for our MySQL
server. someClass (actually called initid) is a structure that is used
to communicate with the server. The manual says:

char *ptr

A pointer that the function can use for its own purposes. For example,
functions can use initid->ptr to communicate allocated memory among
themselves. xxx_init() should allocate the memory and assign it to
this pointer: initid->ptr = allocated_memory; In xxx() [my function
foo] and xxx_deinit(), refer to initid->ptr to use or deallocate the
memory.

And I really use that function a zillion times, its result is used in an
on clause of a self join of a table that can have up to 40,000 entries.
In a first version of that function I was so silly to allocate and
deallocate the memory in foo() itself because I thought the strings the
function takes as arguments can vary in length. After realizing that in
foo_init() I am told about the maximum length and moving (de)allocation
out to foo_init() and foo_deinit() the select statement was about 100
times faster. But it still needs quite a lot of time that's why I'm
anxious to avoid the creation of variables. They probably cause much
less harm than newing an deleting objects. But still if I can get away
with aliases (to avoid the repeated casts), I'd like to do so.

Ralf
 
J

Jonathan Lee

I don't have a choice.

Fair enough.
But still if I can get away with aliases (to avoid the
repeated casts), I'd like to do so.

I think the pointer which I called p2 above, should be fine for that
purpose. The reference won't gain you anything.

Some of your other questions which I didn't answer before:
Furthermore, does the creation of the reference lead
to substantial overload?

No. It should be comparable to having a pointer. Under certain
circumstances it probably doesn't create any overhead at all. For
example, in my previous post I made pr a reference to p2, but their in
the same scope. I'm sure any decent compiler will treat this literally
as an alias. That is, accessing through pr would be as cheap as
accessing p2 directly.
What about the reinterpret_cast, is it done during
compilation?

Not _absolutely_ sure on this one, but I'd say yes. There's no run
time check performed in any event. It just reinterprets the bit
pattern inside the variable to be something else. Take, for example, a
pointer on a x86 CPU. If this pointer is in a general purpose register
and is cast to a "unsigned long", I doubt anything actually happens.
In this particular case, all that needs to be done is that the
compiler needs to know to treat the value as the new type. This could
be different on a system that has different sized pointer and general
purpose registers. Still, I think the reinterpret_cast<> of a pointer
will basically be a copy (maybe with truncate or zero extend).

Note that this may not respect pointer alignment, or even range. Hence
my previous warning about the cast.

Others may have more to add about the mechanics of
reinterpret_cast<> ...

--Jonathan
 
B

Bart van Ingen Schenau

Ralf said:
Jonathan said:

Hi Jonathan,
The result of reinterpret_cast<>() is an rvalue. It can't be
referenced, or used to initialize a reference. That's more or less
what the error message is saying.
Okay.

Note also that reinterpret_cast<>() is pretty much an all around bad
idea. Especially for circumventing the type system, as you seem to
have done. Personally, I would have define a constructor for
someOtherClass() that accepted your char*, then create an instance of
your object and act on that. Copying it back out if need be. If your
code truly runs "a zillion" times (heh) this shouldn't be costly to
do.

I don't have a choice. foo() is a "User Defined Function" for our
MySQL server. someClass (actually called initid) is a structure that
is used to communicate with the server. The manual says:

char *ptr

A pointer that the function can use for its own purposes. For
example, functions can use initid->ptr to communicate allocated
memory among themselves. xxx_init() should allocate the memory and
assign it to this pointer: initid->ptr = allocated_memory; In xxx()
[my function foo] and xxx_deinit(), refer to initid->ptr to use or
deallocate the memory.

As long as you ensure that ptr actually points to an object of type
someOtherClass, then your reinterpret_cast is safe.
But I would submit a bug-report to MySQL that ptr should have the type
'void*' as that matches better with its intended purpose. (And then you
would be able to use static_cast, which is less of a red-flag.)

As for the creation of variables, I would expect (nearly) identical code
for both of these:
void foo(initid* s) {
someOtherClass* ptr(reinterpret_cast<someOtherClass*>(s->ptr));
/* ... */
}
and
void foo(initid* s) {
someOtherClass& ref(*reinterpret_cast<someOtherClass*>(s->ptr));
/* ... */
}

They probably cause much less harm than newing an deleting objects.

Local variables (stack allocated) are several orders of magnitude faster
to create than dynamically allocating the same.
But still if I can get away with aliases (to avoid the repeated
casts), I'd like to do so.

Either an alias (reference) or a correctly typed pointer will work here.
It is likely that the reinterpret_cast will result in zero assembly
instructions.

Bart v Ingen Schenau
 

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,744
Messages
2,569,482
Members
44,900
Latest member
Nell636132

Latest Threads

Top