Reference to pointer to const

P

Paul N

Consider the following bit of code:

int find(char * & in, char ch) {
for ( ; *in; in++) if (*in == ch) return 1;
return 0; }

void replaceonce(char *in, char from, char to) {
if (find(in, from)) *in = to; }

It compiles fine and seems to work OK.

However, since "find" doesn't alter the string, it might be a good
idea to use a "const". But if I change it to:

int find(const char * & in, char ch) {
for ( ; *in; in++) if (*in == ch) return 1;
return 0; }

void replaceonce(char *in, char from, char to) {
if (find(in, from)) *in = to; }

then this doesn't work. VC++ won't compile it at all, saying:

error C2664: 'find' : cannot convert parameter 1 from 'char *' to
'const char *&'

Turbo C++ will compile it, with a warning:

Warning C:\CPP\REFTEST.CPP 9: Temporary used for parameter 'in' in
call to 'find(const char far* far&,char)' in function replaceonce(char
far*,char,char)

and sure enough, it modifies something other than "in".

What I'm trying to do seems reasonable - is there something obvious
that I'm missing?

Thanks.
Paul.
 
I

Ian Collins

Consider the following bit of code:

int find(char *& in, char ch) {
for ( ; *in; in++) if (*in == ch) return 1;
return 0; }

Why are you using a reference?
void replaceonce(char *in, char from, char to) {
if (find(in, from)) *in = to; }

It compiles fine and seems to work OK.

However, since "find" doesn't alter the string, it might be a good
idea to use a "const". But if I change it to:

int find(const char *& in, char ch) {
for ( ; *in; in++) if (*in == ch) return 1;
return 0; }

void replaceonce(char *in, char from, char to) {
if (find(in, from)) *in = to; }

then this doesn't work. VC++ won't compile it at all, saying:

char* and const char* are different types.

Just change find to int find(const char* in, char ch)
 
P

Paul N

Why are you using a reference?

In this example I'm using a reference so I can return both whether the
character was found, and where it was found. Which gets used in the
replaceonce function.

(In the actual code I'm looking for hexadecimal numbers, and want to
keep track of how much I've processed so far.)
char* and const char* are different types.

Just change find to int find(const char* in, char ch)

I think I'd need int find(const char** in, char ch) to get the
position back. Which is doable, of course. But I try to use references
for this sort of thing if possible nowadays.

Thanks.
Paul.
 
K

Kai-Uwe Bux

Paul said:
In this example I'm using a reference so I can return both whether the
character was found, and where it was found. Which gets used in the
replaceonce function.

(In the actual code I'm looking for hexadecimal numbers, and want to
keep track of how much I've processed so far.)


I think I'd need int find(const char** in, char ch) to get the
position back. Which is doable, of course. But I try to use references
for this sort of thing if possible nowadays.

Your find() function has side-effects on the input parameter. It requires
careful use and can lead to loss of the beginning of a string:

char* buffer = new char [length];
read_some_stuff_into_buffer;
find( buffer, 'c' );
delete( buffer ); // oops buffer is not right anymore.

That's why your find() function is a little problematic. Also, it cannot be
called on temporary strings (e.g., returned from functions) as non-const
references cannot be initialized from temporaries.


Instead, you could use:

char* find ( char* str, char c ) {
while ( *str ) {
if ( *str == c ) {
return ( str );
}
++str;
}
return ( 0 );
}

Here, a non-null return indicates that and where the character was found.

As for the problem of const vs. non-const, I feel that overloading both
versions would be correct. E.g., something like this:

char const * find ( char const * str, char c ) {
while ( *str ) {
if ( *str == c ) {
return ( str );
}
++str;
}
return ( 0 );
}

char * find ( char * str, char c ) {
return
const_cast< char * > ( find( const_cast< char const * >( str ), c ) );
}


Then replaceonce() could be something like:

void replaceonce(char *in, char from, char to) {
char* where = find( in, from );
if ( where ) {
*where = to;
}
}


Alternatively, you could do:

char* find ( char* str, char c ) {
while ( *str && *str != c ) { ++str; }
return ( str );
}

and

void replaceonce(char *in, char from, char to) {
char* where = find( in, from );
if ( *where ) {
*where = to;
}
}


Best

Kai-Uwe Bux
 
S

subramanian100in

* Kai-Uwe Bux said:
char * find ( char * str, char c ) {
return
const_cast< char * > ( find( const_cast< char const * >( str ), c ) );
}

Best

Kai-Uwe Bux

I am unable to understand the above function. Kindly clarify the
following:

In the aobve function consider the function call:
find( const_cast< char const * >( str ), c )
Here 'str' is already 'pointer to non-const'. You are applying
const_cast<const char*>(str). Here what does
const_cast<const char*> do ? By const_cast I understand the following:

const char* pc_str;
char* p_str = const_cast<const char*>(pc_str);
Here I understand that 'const_cast' is used to cast away the 'const'
of the argument. But in the aobve case, 'str' is already non-const;
hence my doubt. Kindly clarify it.

Also somewhere I read, we should try to avoid casting(explicit type
conversion) especially 'const_cast'. I do not know the reason. But, if
this is true that we should avoid it, kindly let me know if we could
write two separate overloaded 'find()' functions? ie two separate
implementations of the 'find()' functions without one calling the
other. What will be the drawback in this approach ?

Kindly explain.

Thanks
V.Subramanian
 
B

Bart van Ingen Schenau

I am unable to understand the above function. Kindly clarify the
following:

In the aobve function consider the function call:
     find( const_cast< char const * >( str ), c )
Here 'str' is already 'pointer to non-const'. You are applying
const_cast<const char*>(str). Here what does
const_cast<const char*> do ? By const_cast I understand the following:

const char* pc_str;
char* p_str = const_cast<const char*>(pc_str);
That should probably be:
char* p_str = const_cast said:
Here I understand that 'const_cast' is used to cast away the 'const'
of the argument. But in the aobve case, 'str' is already non-const;
hence my doubt. Kindly clarify it.

In this case, the const_cast is used to *add* a const qualification.
The result is that the overload-resolution for the call to find() will
now select the const version, instead of making a recursive call to
the non-const version.
Also somewhere I read, we should try to avoid casting(explicit type
conversion) especially 'const_cast'. I do not know the reason. But, if
this is true that we should avoid it, kindly let me know if we could
write two separate overloaded 'find()' functions? ie two separate
implementations of the 'find()' functions without one calling the
other. What will be the drawback in this approach ?

You could write two implementations of the find() function, but that
has the drawback that you have to do the same work twice. And if you
find an error in one implementation, it is very easy to forget to
update the other one as well.
Kindly explain.

Thanks
V.Subramanian

Bart v Ingen Schenau
 
A

Andrey Tarasevich

Paul said:
...
What I'm trying to do seems reasonable - is there something obvious
that I'm missing?
...

A reference of type `const char *&` cannot be bound to an object of
`char *` type because that would open the possibility of circumventing
the rules of const-correctness without forcing the user to use an
explicit cast.

This is actually the same issue that one runs into when trying to do this

char *p;
const char **cp = &p; // ERROR. Why?

The question is asked so often that it made its way into the FAQ

http://www.parashift.com/c++-faq-lite/const-correctness.html#faq-18.17

If you replace one level of pointer indirection with a reference (i.e.
change `**` to `*&`) , you can still easily implement the same
circumvention of const-correctness, which would be possible if `char *`
to `const char *&` conversion were allowed:

const char c = 0;
char *non_const_p; // Can we make it point to `c`?

const char *&ref_const_p = non_const_p;
// OK, if we assume that this is allowed

ref_const_p = &c; // perfectly OK
// Done! Now we have `non_const_p` pointing to `c`
// Const-correctness is circumvented
 

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
473,769
Messages
2,569,580
Members
45,055
Latest member
SlimSparkKetoACVReview

Latest Threads

Top