CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Page 1 of 2 12 LastLast
Results 1 to 15 of 22
  1. #1
    Join Date
    Feb 2005
    Location
    Denver
    Posts
    353

    const return values

    Take the following code...
    Code:
     
    const char* fn1 ()
    {
    
    return new char;
    } const char** fn2 () {
    return new char*;
    }
    fn2() generates the following compiler error...

    Error: Cannot return char** from a function that should return const char**.

    ...why?

    It seems to me that if fn1 is valid, why not fn2? Or, if fn2 is not valid, then why should fn1 be valid? I very rarely work with pointer to pointers, but a coworker recently had a problem with this and we narrowed it down to this issue. I had no reasonable explanation but I've been able to greatly simplify and duplicate his exact problem with the above code. If someone can explain this it would be greatly appreciated. Thank you.

  2. #2
    Join Date
    Feb 2002
    Posts
    5,757

    Re: const return values

    consistency

    new char const *[1]

    Kuphryn

  3. #3
    Join Date
    Feb 2005
    Location
    Denver
    Posts
    353

    Re: const return values

    Quote Originally Posted by kuphryn
    consistency

    new char const *[1]

    Kuphryn
    What do you mean by "consistency"? Obviously adding the const will work, the question is why is it necessary? Any receiving variable would of course have to be declared const. If you're saying any variable being returned from within the function(s) would have to be declared const, then I would have to disagree. Besides, fn1() doesn't declare its return value as const, and the compiler has no problem with this at all. Also, I return non-const variables from methods/functions that return const values all the time into const variables.

  4. #4
    Join Date
    Feb 2002
    Posts
    5,757

    Re: const return values

    a *b = new a
    return &a

    Kuphryn

  5. #5
    Join Date
    Oct 2000
    Location
    London, England
    Posts
    4,773

    Re: const return values

    because const in front of char ** does not add constness to the place where you wanted to add it. Therefore you cannot convert char ** to const char **. You can convert char ** to char * const * which is what you are trying to do.

    Why can't you convert char ** to const char **? Because to do so would allow this:

    Code:
    const char * literal1 = "aaaaa";
    char text[] = "bbbbb";
    char * ptr2 = text; // legal. We're allowed to modify this
    char ** pptr2 = &ptr2; // legal
    const char ** pptr1 = (char **) pptr2; // illegal so C-cast it
    
    *pptr1 = literal1; // allowed because the pointer itself is not const
     // it's a pointer to const char * and literal1 is a const char *
    ptr2 = *pptr2; // legal
    ptr2[0] = 'c';
    Which character did we change (or try to change) to 'c'?

  6. #6
    Join Date
    Feb 2005
    Location
    Denver
    Posts
    353

    Re: const return values

    Quote Originally Posted by NMTop40
    because const in front of char ** does not add constness to the place where you wanted to add it. Therefore you cannot convert char ** to const char **. You can convert char ** to char * const * which is what you are trying to do.

    Why can't you convert char ** to const char **? Because to do so would allow this:

    Code:
    const char * literal1 = "aaaaa";
    char text[] = "bbbbb";
    char * ptr2 = text; // legal. We're allowed to modify this
    char ** pptr2 = &ptr2; // legal
    const char ** pptr1 = (char **) pptr2; // illegal so C-cast it
     
    *pptr1 = literal1; // allowed because the pointer itself is not const
    // it's a pointer to const char * and literal1 is a const char *
    ptr2 = *pptr2; // legal
    ptr2[0] = 'c';
    Which character did we change (or try to change) to 'c'?
    Ok, I guess I'm slow. I'm still confused. You're assignment (ptr2[0]='c' is obviously trying to alter the literal string "aaaaa", which you cannot do. In fact, the code will crash if you try, and that is exactly what it should do. I do not what any of the pointers to be const. I want the memory pointed to to be const. In other words, I want a pointer to a pointer to a const char. And that is exactly what you've done in your example. The line that troubles me is the one that is marked illegal. As it stands it will not compile unless you cast using (const char**). Why? You should be able take a non-const variable and assign it to a const variable. The receiving variable simple won't be able to change the contents. In this case, the memory pointed to by the pointer to the pointer. Here is another way to look at it...
    Code:
    char* p = new char;
    const char* cp = p;   // no problem, perfectly legal
     
    char** pp = new char*;
    const char** cpp = pp;  // illegal, why????  I don't see the difference.

  7. #7
    Join Date
    Apr 2006
    Location
    Nr Cambridge, UK
    Posts
    263

    Re: const return values

    They are very different. Here's your example so that the conversions are the same:
    Code:
    char* p = new char;
    const char* cp = p;   // no problem, perfectly legal
     
    char** pp = new char*;
    char* const* cpp = pp;  // no problem, perfectly legal
    NMTop40's example shows how if the conversion you want to be legal were legal, it would allow you to modify const variables without having to do a const_cast (or C style cast). Implicit conversions should not allow you do do anything as dangerous as that.

  8. #8
    Join Date
    Oct 2000
    Location
    London, England
    Posts
    4,773

    Re: const return values

    Quote Originally Posted by sszd
    Ok, I guess I'm slow. I'm still confused. You're assignment (ptr2[0]='c' is obviously trying to alter the literal string "aaaaa", which you cannot do.
    It doesn't know what string it is modifying, but every statement in there does not break constness except for the one that has a C-cast in it, which is the one that you think should be legal. I am showing you how it breaks constness.
    In fact, the code will crash if you try, and that is exactly what it should do. I do not what any of the pointers to be const. I want the memory pointed to to be const.
    It will give undefined behaviour, which may result in a crash.
    In other words, I want a pointer to a pointer to a const char. And that is exactly what you've done in your example.

    The line that troubles me is the one that is marked illegal. As it stands it will not compile unless you cast using (const char**). Why? You should be able take a non-const variable and assign it to a const variable.
    You have a pointer to a non-const pointer to const data. So you can change that it points to. You can change it to point to another pointer to const data.

    The problem is that will leave your pointer to a pointer to non-const data also pointing to const data.

    Remember how you set pointers in C from a function. You pass a pointer to your poniter to the function and it puts something in there.

    Now, say that the function prototype is const char **. And suppose you pass in char **. That means you think you are getting back a pointer to char * but instead you are getting back a pointer to const char *. You think you can modify the data but you can't.

    Here is another way to look at it to show you why it's illegal. Assume that this is C or C++.
    Code:
    void getPointer( const char * * data );
    
    int main()
    {
       char ** ptr;
       getPointer( ptr );
    }
    You think that should compile? After all you are converting ptr from char** to const char**. But *ptr is char *, not const char*.

  9. #9
    Join Date
    Feb 2005
    Location
    Denver
    Posts
    353

    Re: const return values

    Quote Originally Posted by TomWidmer
    They are very different. Here's your example so that the conversions are the same:

    Code:
    char* p = new char;
    const char* cp = p; // no problem, perfectly legal
    char** pp = new char*;
    char* const* cpp = pp; // no problem, perfectly legal

    So what you are telling me is that the declarations...
    Code:
    char** pp;
    ...and...
    Code:
    char* const* pp;
    ...are exactly equivalent? Which means you have declared a non-const pointer to a const pointer to a non-const char. If that's the case, how would you ever declare a non-const pointer to a non-const pointer to const char???
    Quote Originally Posted by TomWidmer
    NMTop40's example shows how if the conversion you want to be legal were legal, it would allow you to modify const variables without having to do a const_cast (or C style cast).
    I disagree. If...
    Code:
    const char** pptr1 = pptr2;
    ...were legal, and it truely meant you were assigning a non-const pointer to a non-const pointer to a const char, then you could modify pptr1 and *pptr1. You just wouldn't be allowed to modify **pptr1. However, since everything about pptr2 is still non-const, you could modify any part of pptr2 (i.e. pptr2, *pptr2, and even **pptr2).

    Quote Originally Posted by NMTop40
    It doesn't know what string it is modifying, but every statement in there does not break constness except for the one that has a C-cast in it, which is the one that you think should be legal. I am showing you how it breaks constness.
    How are you breaking constness if nothing has been declared const? Example...
    Code:
    char c;
    char* p = &c;
    char** pp = &p;			// Is this really an implied char* const *???
    const char** cpp = pp; // illegal, breaking constness???
    c is not const
    p is not const
    *p is not const
    pp is not const
    *pp is not const
    **pp is not const

    Unless you are saying (as I mentined above to TomWidmer) that...
    Code:
    char** pp = &p;
    ...is really the same as...
    Code:
    char* const* pp = &p;
    If that is true, then I can see how you are breaking constness. But, if this is true, you would never be allowed to declare a non-const pointer to a non-const pointer to a char (char**). Is this what you are saying? In other words...
    Code:
    char* const *				 // legal
    char* const *const		 // legal
    const char* const *		 // legal
    const char* const *const // legal
    char**						 // illegal???, or implied char* const *
    const char**				 // illegal???, or implied const char* const *
    Quote Originally Posted by NMTop40
    Here is another way to look at it to show you why it's illegal. Assume that this is C or C++.
    Code:
    void getPointer( const char * * data );
     
    int main()
    {
    char ** ptr;
    getPointer( ptr );
    }
    You think that should compile? After all you are converting ptr from char** to const char**. But *ptr is char *, not const char*.
    Why not??? After all, it is the receiving function that has a declared const variable that it won't be able to modify. Besides, I can use that exact same argument for the following...
    Code:
    void getPointer (const char* data);
     
    int main ()
    {
    
    char* ptr; getPointer (ptr);
    }
    This does compile. But why should it?? After all, *ptr is a char, not a const char.
    Last edited by sszd; September 1st, 2006 at 11:48 AM.

  10. #10
    Join Date
    Apr 2006
    Location
    Nr Cambridge, UK
    Posts
    263

    Re: const return values

    Quote Originally Posted by sszd
    So what you are telling me is that the declarations...
    Code:
    char** pp;
    ...and...
    Code:
    char* const* pp;
    ...are exactly equivalent?
    No, not at all. One is a pointer to pointer to char, the other is a pointer to a const pointer to char. What I am saying is that it is possible to convert T* to const T*. In the first example, T is char, in the second example, T is char*. If you still don't understand NMTop40's example, see here: http://www.parashift.com/c++-faq-lit...html#faq-18.17

  11. #11
    Join Date
    Oct 2000
    Location
    London, England
    Posts
    4,773

    Re: const return values

    My code is this though:

    Code:
    void getPointer( const char ** pptr );
    
    int main()
    {
       char * ptr;
       getPointer( &ptr );
    }
    Well that's really how you should call it because in my previous example it is likely to set a dangling pointer.

    But if you want to pass it a char ** then

    Code:
    int main()
    {
       char * ptr;
       char ** pptr = &ptr;
       getPointer( pptr );
    }
    The function does not only say that it will not modify something, it is also saying it will "return" (by setting your parameter) a pointer to const. But your pointer is not to const and so your function could modify it.

    Maybe getPointer is

    Code:
    void getPointer( const char ** ptr )
    {
       *ptr = "aaaaa";
    }
    Perfectly valid as *ptr is const char *.

  12. #12
    Join Date
    Sep 2004
    Posts
    519

    Re: const return values

    A reason const is confusing is that:

    Code:
    typedef const char* type;
    is the same as:

    Code:
    typedef char const * type;
    Note that the first case is the exceptional case because const "ties to" the type preceeding it except if there is a const in the beginning then it "ties to" the type that follows it.

    (sorry for the very vague and possible incorrect language here. english isn't my native language and thus I've problems communicating the semantics. Perhaps someone could provide the standard's definition?)

    IMO this is confusing but legal:
    Code:
    typedef const char * const type;
    Where this is more "logical":
    Code:
    typedef char const * const type;
    They both means the same thing. A const pointer pointing to const char(s).

    IMO: Don't use the optional syntax. Declare your const "strings" like this:
    Code:
    typedef char const * type;
    Hope this helps

    PS. Volatile follows the same confusing scheme allowing for confusing constructs such as this:

    Code:
    typedef volatile char const * const volatile type;
    Which of course means a const volatile pointer pointing to const volatile char(s)
    Last edited by marten_range; September 1st, 2006 at 12:29 PM.

  13. #13
    Join Date
    Feb 2005
    Location
    Denver
    Posts
    353

    Re: const return values

    Ok, after reading the link sent by TomWidmer it made a lot more sense. Although, I then went back and re-examined NMTop40's code which looks very similar and don't know why I didn't see this the first time. Like I said, I guess I'm slow.

    Anyway, my curiosity has still got the better of me. I would like to see a valid assignment for the following declaration without casting constness away...
    Code:
    const char** cpp = ???;
    Also, I tried the following and am confused...
    Code:
    const char c = 'A';
    char* p;
    const char** cpp = static_cast<const char* const*> (&p);  // Why is this allowed???
    *cpp = &c;  // Because now you can do this
    *p = 'B';	 // and this.
    I would think the assignment to cpp would generate a compiler error. Note that no constness has been removed, only added (we have cast to a non-const pointer to a const pointer to a const char). But then it looks as if the inside const pointer is implicitly removed since the declaration is for non-const pointers. Could this possibly be a compiler bug???

  14. #14
    Join Date
    Apr 2006
    Location
    Nr Cambridge, UK
    Posts
    263

    Re: const return values

    Quote Originally Posted by sszd
    Anyway, my curiosity has still got the better of me. I would like to see a valid assignment for the following declaration without casting constness away...
    Code:
    const char** cpp = ???;
    Not sure quite what you want here, but do you mean this:
    Code:
    const char* cp = "foo";
    const char**cpp = &cp;
    Quote Originally Posted by sszd
    Also, I tried the following and am confused...
    Code:
    const char c = 'A';
    char* p;
    const char** cpp = static_cast<const char* const*> (&p);  // Why is this allowed???
    *cpp = &c;  // Because now you can do this
    *p = 'B';	 // and this.
    I would think the assignment to cpp would generate a compiler error. Note that no constness has been removed, only added (we have cast to a non-const pointer to a const pointer to a const char). But then it looks as if the inside const pointer is implicitly removed since the declaration is for non-const pointers. Could this possibly be a compiler bug???
    Yes, the code should not compile - the assignment of the return of the static_cast to cpp is not valid, since it is removing a const. What's your compiler?

  15. #15
    Join Date
    Feb 2005
    Location
    Denver
    Posts
    353

    Re: const return values

    Quote Originally Posted by sszd
    Also, I tried the following and am confused...
    Code:
    const char c = 'A';
    char* p;
    const char** cpp = static_cast<const char* const*> (&p); // Why is this allowed???
    *cpp = &c; // Because now you can do this
    *p = 'B'; // and this.

    I would think the assignment to cpp would generate a compiler error. Note that no constness has been removed, only added (we have cast to a non-const pointer to a const pointer to a const char). But then it looks as if the inside const pointer is implicitly removed since the declaration is for non-const pointers. Could this possibly be a compiler bug???
    Quote Originally Posted by TomWidmer
    Yes, the code should not compile - the assignment of the return of the static_cast to cpp is not valid, since it is removing a const. What's your compiler?
    The platform is a SunBlade 2500 running SunOS 5.8. The complier is Sun C++ 5.6.

Page 1 of 2 12 LastLast

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured