Reference to pointer to const

Discussion in 'C++' started by Paul N, Aug 11, 2010.

  1. Paul N

    Paul N Guest

    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.
     
    Paul N, Aug 11, 2010
    #1
    1. Advertising

  2. Paul N

    Ian Collins Guest

    On 08/12/10 08:52 AM, Paul N wrote:
    > 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)

    --
    Ian Collins
     
    Ian Collins, Aug 11, 2010
    #2
    1. Advertising

  3. Paul N

    Paul N Guest

    On 11 Aug, 22:01, Ian Collins <> wrote:
    > On 08/12/10 08:52 AM, Paul N wrote:
    >
    > > 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?


    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.)

    > > 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)


    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.
     
    Paul N, Aug 11, 2010
    #3
  4. Paul N

    Kai-Uwe Bux Guest

    Paul N wrote:

    > On 11 Aug, 22:01, Ian Collins <> wrote:
    >> On 08/12/10 08:52 AM, Paul N wrote:
    >>
    >> > 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?

    >
    > 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.)
    >
    >> > 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)

    >
    > 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
     
    Kai-Uwe Bux, Aug 11, 2010
    #4
  5. Paul N

    , India Guest

    * Kai-Uwe Bux <> wrote:
    > Paul N wrote:
    > > On 11 Aug, 22:01, Ian Collins <> wrote:
    > >> On 08/12/10 08:52 AM, Paul N wrote:

    >
    > 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
     
    , India, Aug 12, 2010
    #5
  6. On Aug 12, 2:10 pm, ", India"
    <> wrote:
    > * Kai-Uwe Bux <> wrote:
    >
    > > Paul N wrote:
    > > > On 11 Aug, 22:01, Ian Collins <> wrote:
    > > >> On 08/12/10 08:52 AM, Paul N wrote:

    >
    > >   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);

    That should probably be:
    char* p_str = const_cast<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.


    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
     
    Bart van Ingen Schenau, Aug 12, 2010
    #6
  7. Paul N wrote:
    > ...
    > 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

    --
    Best regards,
    Andrey Tarasevich
     
    Andrey Tarasevich, Aug 12, 2010
    #7
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. coala
    Replies:
    3
    Views:
    414
    coala
    Sep 6, 2006
  2. coala
    Replies:
    1
    Views:
    614
    Victor Bazarov
    Sep 6, 2006
  3. Javier
    Replies:
    2
    Views:
    622
    James Kanze
    Sep 4, 2007
  4. George2
    Replies:
    10
    Views:
    638
    Pete Becker
    Dec 17, 2007
  5. Disc Magnet
    Replies:
    1
    Views:
    654
    Ian Collins
    May 6, 2010
Loading...

Share This Page