What's the difference between "Type&..­" with "const Type&.."

Discussion in 'C++' started by fl, Dec 30, 2007.

  1. fl

    fl Guest

    Hi,
    I am new to C++. The following are from the example of book C primer.
    I don't know the difference of them even after I look through the
    book. Especially the second "const" of the last line is curious to me.
    Thank you in advance.




    // return element from head of Queue
    // unchecked operation: front on an empty Queue is undefined
    Type& front() { return head->item; }
    const Type &front() const { return head->item; }
    fl, Dec 30, 2007
    #1
    1. Advertising

  2. fl

    Jim Langston Guest

    fl wrote:
    > Hi,
    > I am new to C++. The following are from the example of book C primer.
    > I don't know the difference of them even after I look through the
    > book. Especially the second "const" of the last line is curious to me.
    > Thank you in advance.
    >
    >
    >
    >
    > // return element from head of Queue
    > // unchecked operation: front on an empty Queue is undefined
    > Type& front() { return head->item; }


    front returns a reference to a Type that is modifiable (not constant) and
    the function can change the instance of the class it was called on.

    > const Type &front() const { return head->item; }


    front returns a constant type reference (the instance of Type can not be
    changed via the reference, it's constant) and the function can not change
    the instance of the class it was called on. The function itself is
    constant.

    --
    Jim Langston
    Jim Langston, Dec 30, 2007
    #2
    1. Advertising

  3. fl

    fl Guest

    On 30 déc, 17:43, "Jim Langston" <> wrote:
    > fl wrote:
    > > Hi,
    > > I am new to C++. The following are from the example of book C primer.
    > > I don't know the difference of them even after I look through the
    > > book. Especially the second "const" of the last line is curious to me.
    > > Thank you in advance.

    >
    > > // return element from head of Queue
    > > // unchecked operation: front on an empty Queue is undefined
    > > Type& front()             { return head->item; }

    >
    > front returns a reference to a Type that is modifiable (not constant) and
    > the function can change the instance of the class it was called on.
    >
    > > const Type &front() const { return head->item; }

    >
    > front returns a constant type reference (the instance of Type can not be
    > changed via the reference, it's constant) and the function can not change
    > the instance of the class it was called on.  The function itself is
    > constant.
    >
    > --
    > Jim Langston
    >


    Thank you very much. Both of the functions have the same function
    body. There are four combinations with "const" and non-const in the
    two definitions. The two definitions give two of the specific types to
    exclude the other two:
    const Type &front() { return head->item; }
    Type &front() const { return head->item; }

    Right?
    fl, Dec 30, 2007
    #3
  4. fl

    Jim Langston Guest

    fl wrote:
    > On 30 déc, 17:43, "Jim Langston" <> wrote:
    >> fl wrote:
    >>> Hi,
    >>> I am new to C++. The following are from the example of book C
    >>> primer. I don't know the difference of them even after I look
    >>> through the book. Especially the second "const" of the last line is
    >>> curious to me. Thank you in advance.

    >>
    >>> // return element from head of Queue
    >>> // unchecked operation: front on an empty Queue is undefined
    >>> Type& front() { return head->item; }

    >>
    >> front returns a reference to a Type that is modifiable (not
    >> constant) and the function can change the instance of the class it
    >> was called on.
    >>
    >>> const Type &front() const { return head->item; }

    >>
    >> front returns a constant type reference (the instance of Type can
    >> not be changed via the reference, it's constant) and the function
    >> can not change the instance of the class it was called on. The
    >> function itself is constant.
    >>
    >> --
    >> Jim Langston
    >>

    >
    > Thank you very much. Both of the functions have the same function
    > body. There are four combinations with "const" and non-const in the
    > two definitions. The two definitions give two of the specific types to
    > exclude the other two:
    > const Type &front() { return head->item; }
    > Type &front() const { return head->item; }
    >
    > Right?


    Both of these function declarations should be front() const for constant
    correctness. The function does not modify the class.

    However, you can't do this, as you can't override a function by return value
    only. It seems that it would make more sense for there to be only one
    function declaration:

    Type& front() const { return head->item; }

    The general rule is, use const wherever you can for constant correctness.
    If a function does not modify the instance, declare if const. If the
    parameters are not modified by the function, declare them const. This
    applies to pointers and references, it has a little different effect on
    biult in types. I.E.

    void Foo( const int i ) { /*...*/ }
    changes to i can not be seen outside the function since they are passed by
    value anyway. However, it means that you can't change i inside the function
    itself which some people may do (I've never liked that though).

    I.e.
    void Count( int i ) { while ( i > 0 ) std::cout << i-- << "\n"; }

    You can't do that if it is Count( const int i ).

    I don't think most people bother to make built in types const, or rather
    I've found no real meaningful reason too.

    You should read the C++ FAQ on "const correctness". It explains it a lot
    better than I can.
    http://www.new-brunswick.net/workshop/c /faq/const-correctness.html


    --
    Jim Langston
    Jim Langston, Dec 30, 2007
    #4
  5. fl

    Jim Langston Guest

    Jim Langston wrote:
    > fl wrote:
    >> On 30 déc, 17:43, "Jim Langston" <> wrote:
    >>> fl wrote:
    >>>> Hi,
    >>>> I am new to C++. The following are from the example of book C
    >>>> primer. I don't know the difference of them even after I look
    >>>> through the book. Especially the second "const" of the last line is
    >>>> curious to me. Thank you in advance.
    >>>
    >>>> // return element from head of Queue
    >>>> // unchecked operation: front on an empty Queue is undefined
    >>>> Type& front() { return head->item; }
    >>>
    >>> front returns a reference to a Type that is modifiable (not
    >>> constant) and the function can change the instance of the class it
    >>> was called on.
    >>>
    >>>> const Type &front() const { return head->item; }
    >>>
    >>> front returns a constant type reference (the instance of Type can
    >>> not be changed via the reference, it's constant) and the function
    >>> can not change the instance of the class it was called on. The
    >>> function itself is constant.
    >>>
    >>> --
    >>> Jim Langston
    >>>

    >>
    >> Thank you very much. Both of the functions have the same function
    >> body. There are four combinations with "const" and non-const in the
    >> two definitions. The two definitions give two of the specific types
    >> to exclude the other two:
    >> const Type &front() { return head->item; }
    >> Type &front() const { return head->item; }
    >>
    >> Right?

    >
    > Both of these function declarations should be front() const for
    > constant correctness. The function does not modify the class.
    >
    > However, you can't do this, as you can't override a function by
    > return value only. It seems that it would make more sense for there
    > to be only one function declaration:
    >
    > Type& front() const { return head->item; }
    >
    > The general rule is, use const wherever you can for constant
    > correctness. If a function does not modify the instance, declare if
    > const. If the parameters are not modified by the function, declare
    > them const. This applies to pointers and references, it has a little
    > different effect on biult in types. I.E.
    >
    > void Foo( const int i ) { /*...*/ }
    > changes to i can not be seen outside the function since they are
    > passed by value anyway. However, it means that you can't change i
    > inside the function itself which some people may do (I've never liked
    > that though).
    > I.e.
    > void Count( int i ) { while ( i > 0 ) std::cout << i-- << "\n"; }
    >
    > You can't do that if it is Count( const int i ).
    >
    > I don't think most people bother to make built in types const, or
    > rather I've found no real meaningful reason too.
    >
    > You should read the C++ FAQ on "const correctness". It explains it a
    > lot better than I can.
    > http://www.new-brunswick.net/workshop/c /faq/const-correctness.html


    Specially, 18.12 seems to deal with what you are looking at.
    http://www.new-brunswick.net/workshop/c /faq/const-correctness.html#faq-18.12

    --
    Jim Langston
    Jim Langston, Dec 30, 2007
    #5
  6. Re: What's the difference between "Type&..­" with "const Type&.."

    On 2007-12-31 00:16, Jim Langston wrote:
    > fl wrote:
    >> On 30 déc, 17:43, "Jim Langston" <> wrote:
    >>> fl wrote:
    >>>> Hi,
    >>>> I am new to C++. The following are from the example of book C
    >>>> primer. I don't know the difference of them even after I look
    >>>> through the book. Especially the second "const" of the last line is
    >>>> curious to me. Thank you in advance.
    >>>
    >>>> // return element from head of Queue
    >>>> // unchecked operation: front on an empty Queue is undefined
    >>>> Type& front() { return head->item; }
    >>>
    >>> front returns a reference to a Type that is modifiable (not
    >>> constant) and the function can change the instance of the class it
    >>> was called on.
    >>>
    >>>> const Type &front() const { return head->item; }
    >>>
    >>> front returns a constant type reference (the instance of Type can
    >>> not be changed via the reference, it's constant) and the function
    >>> can not change the instance of the class it was called on. The
    >>> function itself is constant.
    >>>
    >>> --
    >>> Jim Langston
    >>>

    >>
    >> Thank you very much. Both of the functions have the same function
    >> body. There are four combinations with "const" and non-const in the
    >> two definitions. The two definitions give two of the specific types to
    >> exclude the other two:
    >> const Type &front() { return head->item; }
    >> Type &front() const { return head->item; }
    >>
    >> Right?

    >
    > Both of these function declarations should be front() const for constant
    > correctness. The function does not modify the class.
    >
    > However, you can't do this, as you can't override a function by return value
    > only. It seems that it would make more sense for there to be only one
    > function declaration:
    >
    > Type& front() const { return head->item; }


    Actually the reason for having two versions is that the user should be
    able to modify the object returned (or referred to by the reference
    returned) by front() if the object you called front on is non-const. But
    if the object is const you can not modify the elements.

    This is a common idiom for containers (which I suspect the example is
    taken from) and it is the reason whey both begin() and end() have a
    const and a non-const version on the standard library containers.

    --
    Erik Wikström
    Erik Wikström, Dec 31, 2007
    #6
  7. fl

    Jim Langston Guest

    Erik Wikström wrote:
    > On 2007-12-31 00:16, Jim Langston wrote:
    >> fl wrote:
    >>> On 30 déc, 17:43, "Jim Langston" <> wrote:
    >>>> fl wrote:
    >>>>> Hi,
    >>>>> I am new to C++. The following are from the example of book C
    >>>>> primer. I don't know the difference of them even after I look
    >>>>> through the book. Especially the second "const" of the last line
    >>>>> is curious to me. Thank you in advance.
    >>>>
    >>>>> // return element from head of Queue
    >>>>> // unchecked operation: front on an empty Queue is undefined
    >>>>> Type& front() { return head->item; }
    >>>>
    >>>> front returns a reference to a Type that is modifiable (not
    >>>> constant) and the function can change the instance of the class it
    >>>> was called on.
    >>>>
    >>>>> const Type &front() const { return head->item; }
    >>>>
    >>>> front returns a constant type reference (the instance of Type can
    >>>> not be changed via the reference, it's constant) and the function
    >>>> can not change the instance of the class it was called on. The
    >>>> function itself is constant.
    >>>>
    >>>> --
    >>>> Jim Langston
    >>>>
    >>>
    >>> Thank you very much. Both of the functions have the same function
    >>> body. There are four combinations with "const" and non-const in the
    >>> two definitions. The two definitions give two of the specific types
    >>> to exclude the other two:
    >>> const Type &front() { return head->item; }
    >>> Type &front() const { return head->item; }
    >>>
    >>> Right?

    >>
    >> Both of these function declarations should be front() const for
    >> constant correctness. The function does not modify the class.
    >>
    >> However, you can't do this, as you can't override a function by
    >> return value only. It seems that it would make more sense for there
    >> to be only one function declaration:
    >>
    >> Type& front() const { return head->item; }

    >
    > Actually the reason for having two versions is that the user should be
    > able to modify the object returned (or referred to by the reference
    > returned) by front() if the object you called front on is non-const.
    > But if the object is const you can not modify the elements.
    >
    > This is a common idiom for containers (which I suspect the example is
    > taken from) and it is the reason whey both begin() and end() have a
    > const and a non-const version on the standard library containers.


    Yes, after I posted that I read through the FAQ again to refresh my memory
    when I came across 18.12 which states this exact sample and posted the
    follow up.

    --
    Jim Langston
    Jim Langston, Dec 31, 2007
    #7
  8. fl

    Tobias Guest

    Hello,
    when I red the thread I've got the impression that your question

    > The two definitions give two of the specific types to
    > exclude the other two:
    > const Type &front() { return head->item; }
    > Type &front() const { return head->item; }


    was not clearly answered. You are right. Both constructs should NOT be
    used (assuming that head is a non-mutable member of (*this)).

    The first one is bad style. The function front() should be const since
    it does not change the member and the member can also not be changed
    from the caller.

    The second one should even be rejected by the compiler since returning
    the non-const member-reference gives the caller the possiblility to
    change it (and therefore the object). Thus, the second front function
    is NOT const.

    Hope, this is clearly stated (section 18.11 of the FAQ).

    Best regards,
    Tobias
    Tobias, Dec 31, 2007
    #8
  9. fl

    James Kanze Guest

    On Dec 31 2007, 5:09 pm, Tobias <> wrote:
    > when I red the thread I've got the impression that your question


    > > The two definitions give two of the specific types to
    > > exclude the other two:
    > > const Type &front() { return head->item; }
    > > Type &front() const { return head->item; }


    > was not clearly answered. You are right. Both constructs
    > should NOT be used (assuming that head is a non-mutable member
    > of (*this)).


    > The first one is bad style. The function front() should be
    > const since it does not change the member and the member can
    > also not be changed from the caller.


    > The second one should even be rejected by the compiler since
    > returning the non-const member-reference gives the caller the
    > possiblility to change it (and therefore the object). Thus,
    > the second front function is NOT const.


    The compiler only enforces shallow const. The second one
    returns a reference to something pointed to, so it is fine as
    far as the compiler is concerned. It is still generally bad
    practice, since it allows the client code to modify the logical
    value of the object through a const reference.

    The usual alternatives are, of course:
    Type const& front() const { return head->item ; }
    Type& front() { return head->item ; }
    The first allows no modification, even by the client which calls
    it, and the second allows modification by the client of the
    logical value of the object.

    And of course, which one is called depends on the const-ness of
    the object, and not on what is done with or through the return
    value.

    --
    James Kanze (GABI Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
    James Kanze, Jan 1, 2008
    #9
  10. fl

    Tobias Guest

    /*
    Hello,
    thanks for the replay.
    You wrote:

    > The compiler only enforces shallow const.


    If so -- does

    "gcc version 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)"

    get this wrong?

    Best regards,
    Tobias
    */

    class T
    {
    int x;
    int& getref() const {
    return x;
    }
    };

    /*
    Command line:

    g++ -c test.cc

    Output:

    test.cc: In member function 'int& T::getref() const':
    test.cc:6: error: invalid initialization of reference of type 'int&'
    from expression of type 'const int'

    */
    Tobias, Jan 2, 2008
    #10
  11. fl

    Tobias Guest

    Okay, I get it. What I wrote:

    > class T
    > {
    > int x;
    > int& getref() const {
    > return x;
    > }
    >
    > };
    >


    IS really shallow and therefore the compiler rightly cries.
    It's the pointer-thing. The following will work
    (as it works also for the example of the OP):

    class T
    {
    int *x;
    int& getref() const {
    return *x;
    }

    };

    My fault. Sorry for the noise.

    Best regards,
    Tobias
    Tobias, Jan 2, 2008
    #11
  12. Re: What's the difference between "Type&..­" with "const Type&.."

    On 2008-01-02 09:58, Tobias wrote:
    > /*
    > Hello,
    > thanks for the replay.
    > You wrote:
    >
    >> The compiler only enforces shallow const.

    >
    > If so -- does
    >
    > "gcc version 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)"
    >
    > get this wrong?
    >
    > Best regards,
    > Tobias
    > */
    >
    > class T
    > {
    > int x;
    > int& getref() const {
    > return x;
    > }
    > };


    If the function is const then the return-value should probably also be
    const (or return by value):

    const int& getref() const {
    return x;
    }

    And if you want to be able to modify x through getref() as long as the
    object itself is not const you can add:

    int& getref() {
    return x;
    }

    And test like this:

    int main()
    {
    T t;
    const T& ct = t;
    t.getref() = 5;
    ct.getref() = 4; // will not work since ct is const
    }

    --
    Erik Wikström
    Erik Wikström, Jan 2, 2008
    #12
  13. fl

    James Kanze Guest

    On Jan 2, 9:58 am, Tobias <> wrote:
    > /*
    > You wrote:
    > > The compiler only enforces shallow const.


    > If so -- does


    > "gcc version 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)"


    > get this wrong?


    Not in any case I know of.

    > class T
    > {
    > int x;
    > int& getref() const {
    > return x;
    > }
    > };


    > /*
    > Command line:


    > g++ -c test.cc


    > Output:


    > test.cc: In member function 'int& T::getref() const':
    > test.cc:6: error: invalid initialization of reference of type 'int&'
    > from expression of type 'const int'


    Which is correct. You've violated shallow const, trying to get
    a non-const reference to an immediate member in const member
    function.

    --
    James Kanze (GABI Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
    James Kanze, Jan 2, 2008
    #13
    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. jakk
    Replies:
    4
    Views:
    12,131
  2. Kevin L
    Replies:
    6
    Views:
    887
    Ron Natalie
    Aug 11, 2003
  3. p|OtrEk

    const type& and type const&

    p|OtrEk, Jul 17, 2005, in forum: C++
    Replies:
    6
    Views:
    396
    Ben Pope
    Jul 17, 2005
  4. =?ISO-8859-1?Q?Martin_J=F8rgensen?=

    what's the difference between type struct and type class exactly?

    =?ISO-8859-1?Q?Martin_J=F8rgensen?=, Feb 22, 2006, in forum: C++
    Replies:
    5
    Views:
    504
    =?ISO-8859-1?Q?Martin_J=F8rgensen?=
    Feb 22, 2006
  5. paulo
    Replies:
    9
    Views:
    707
    James Kanze
    Mar 6, 2009
Loading...

Share This Page