Re: Returning Nulls in Templates

Discussion in 'C++' started by Alf P. Steinbach /Usenet, Mar 20, 2011.

  1. * Ruben Safir, on 20.03.2011 06:37:
    > I'm having a very difficult time returning NULLS in my program which
    > started out as an exercise of Linked Lists based on Lippman, but has
    > evolved as I test out new skills and methods. I've templated it an then
    > I added some hooks for MYSQLb but I've run into trouble with returning
    > NULL values of zero's, especially with the operator[] which requires the
    > return value being a reference. Let me copy and past a copy of the
    > entire program, since it is complex for me, but likely to be run of the
    > mill for the advanced C++ programmers here.
    >
    > This is the main header file which was originally broken into a header
    > and a .cpp file but has since been combined to make the templates happy
    > ================================================================================
    > #ifndef LINKLIST_H
    > #define LINKLIST_H
    > #endif


    This '#endif' is too early; it should be at the very end of the file.


    > #include<iostream>
    >
    >
    > namespace CHAINLIST{


    Reserve all uppercase names for macros.

    Don't shout.


    > template<class unk>
    > class NODE{


    Reserve all uppercase names for macros.

    Don't shout.


    > public:
    > NODE<unk>( unk value, NODE<unk> *item_to_link_to = 0);


    There's no need to repeat the template type parameter here.


    > inline unk value();


    It's not necessary to designate the method as 'inline', since it's in a template.

    On the other hand you should have a 'const' at the end there.


    > inline unk& value_ref();
    > inline void value(unk);


    When you have exposed a member in all ways possible, and that's roughly what you
    have done here, what's the point of having that member non-'private'?

    In this case, nothing.

    Remove the accessor and modifier stuff. Just make that value 'public'.


    > inline NODE<unk> * next();


    Ditto, should be 'const'.


    > inline NODE<unk>& next_ref();
    > inline void next(NODE<unk> *);


    Ditto, just make that next-pointer 'public'.


    > NODE<unk> * err_node;
    > unk err_value;


    Uh huh, what's this? Two public data members that apparently serve no purpose.
    In every node instance.

    Think about it.


    > ~NODE<unk>();


    You don't need that non-virtual destructor.

    Either make it virtual (to support class derivation), or remove it.


    >
    > private:
    > unk _value;
    > NODE<unk> *_next;


    When underscores are used to designate data members, the usual convention is to
    put the underscore at the *end* of the name.

    Underscore at front conflicts with the C conventions for linkage names and
    internal names.


    > };
    >

    [snip]


    > template<class unk>
    > inline unk NODE<unk>::value(){
    > if(this)
    > return _value;
    > else{
    > return 0;
    > }
    > }


    'this' is never zero.

    [snipalot]


    Cheers & hth.

    - Alf

    --
    blog at <url: http://alfps.wordpress.com>
     
    Alf P. Steinbach /Usenet, Mar 20, 2011
    #1
    1. Advertising

  2. On 3/20/2011 11:37 AM, Ruben Safir wrote:
    > On Sun, 20 Mar 2011 10:17:04 +0100, Alf P. Steinbach /Usenet wrote:
    >
    >
    >>> template<class unk>
    >>> inline unk NODE<unk>::value(){
    >>> if(this)
    >>> return _value;
    >>> else{
    >>> return 0;
    >>> }
    >>> }

    >>
    >> 'this' is never zero.

    >
    > It can be and has been when the LIST constructor initiates a NODE
    > instance as 0.


    No, it cannot be null without invoking undefined behaviour first.
    Calling a non-static member function using a null pointer has undefined
    behaviour.

    > Then as you walk down the nodes through the list, the final _next is
    > always 0 and this for the _next node is 0x0, according to GDB.
    >
    > Ruben



    --
    I do not respond to top-posted replies, please don't ask
     
    Victor Bazarov, Mar 20, 2011
    #2
    1. Advertising

  3. Alf P. Steinbach /Usenet

    James Kanze Guest

    On Mar 20, 3:36 pm, Ruben Safir <> wrote:
    > On Sun, 20 Mar 2011 10:17:04 +0100, Alf P. Steinbach /Usenet wrote:


    > >> NODE<unk> * err_node;
    > >> unk err_value;


    > > Uh huh, what's this? Two public data members that apparently
    > > serve no purpose. In every node instance.


    > I was having trouble with return values that are returned as references
    > being considered temp, even ~0~, so I tried to create a separate error
    > return. If it would just accept NULL or 0 for all possible types, that
    > would be better. I thought 0 was a macro just for this reason.


    There is no such thing as a null reference. If you need to
    return NULL, return a pointer. (And I'm sure it's a typo, but 0
    isn't a macro. NULL is. But only as a convenience to allow you
    to write more readable code---as far as the compiler is
    concerned, there is absolutely no difference between NULL and
    0.)

    --
    James Kanze
     
    James Kanze, Mar 20, 2011
    #3
  4. Alf P. Steinbach /Usenet

    Noah Roberts Guest

    On 3/21/2011 10:01 AM, Ruben Safir wrote:
    > On Sun, 20 Mar 2011 13:53:17 +0000, Leigh Johnston wrote:
    >
    >> On 20/03/2011 09:17, Alf P. Steinbach /Usenet wrote:
    >>> * Ruben Safir, on 20.03.2011 06:37:
    >>>> inline unk value();
    >>>
    >>> It's not necessary to designate the method as 'inline', since it's in a
    >>> template.
    >>>
    >>> On the other hand you should have a 'const' at the end there.
    >>>
    >>>
    >>>> inline unk& value_ref();
    >>>> inline void value(unk);
    >>>
    >>> When you have exposed a member in all ways possible, and that's roughly
    >>> what you have done here, what's the point of having that member
    >>> non-'private'?
    >>>
    >>> In this case, nothing.
    >>>
    >>> Remove the accessor and modifier stuff. Just make that value 'public'.
    >>>
    >>>

    >> I disagree; instead I would do:
    >>
    >> const unk& value() const;
    >> unk& value();
    >> void set_value(const unk&);
    >>
    >> /Leigh

    >
    > If I define value() as a const returning a const reference, then I can't
    > change the value when using the operator[] and I'd think defeats the
    > purpose of making it a reference in the first place ..
    >
    > mylist[2] = mylust[3];
    >
    > I broke value() into two different methods, one returning the reference
    >
    > unk Node::value() const{
    > return value_;
    > }
    >
    > unk& Node::value_ref(){
    > return value_;
    > }


    In case you are not aware, you can override based on const-ness. For
    example:

    unk Node::value() const { return value_; }
    unk& Node::value() { return value_; }

    --
    http://crazycpp.wordpress.com
     
    Noah Roberts, Mar 21, 2011
    #4
  5. Alf P. Steinbach /Usenet

    James Kanze Guest

    On Mar 21, 2:57 pm, Ruben Safir <> wrote:
    > On Sun, 20 Mar 2011 11:33:04 -0700, James Kanze wrote:
    > > (And I'm sure it's a typo, but 0
    > > isn't a macro. NULL is. But only as a convenience to allow you to
    > > write more readable code---as far as the compiler is concerned, there is
    > > absolutely no difference between NULL and 0.)


    > It wasn't a typo but I meant it. I was misremembering what Stroustrup
    > wrote in his text, in section 5.3.1 page 88 in the third edition.


    > 5.1.1


    > Zero(0) is an int. Because the standard conversions (§C.6.2.3), 0 can be
    > used as a constant of any integral(§4.1.1), floating point, pointer or
    > pointer-to-member type. The type of zero will be determined by context/
    > Zero will typically (but not necessarily) be represented by the bit
    > pattern of all zeros for the appropriate size.


    > No object is allocated with the address o. Consequently, 0 acts as a
    > pointer literal, indicating that a pointer doesn't refer to an object.


    > In C it has been popular to define a Macro NULL to represent the zero
    > pointer. Because of C++'s tighter type checking, the use of plain 0,
    > rather than any suggested NULL macro, leads to fewer problems. If you
    > feel you must define NULL use


    > const int NULL = 0;


    > The const qualifier(§5.4) prevents accidental redefinition of NULL and
    > ensures that NULL can be used where a constant is required.


    That text is extremely dated, and was when the third edition was
    published. It refers to an old problem when C++ used C as an
    intermediate language, and used C's standard headers untouched.

    It is illegal for you to define NULL in your own code. Don't do
    it. Just include the appropriate header.

    > So I was wrong, but Zero has magic properties that NULL doesn't.


    No. An integral constant expression evaluating to 0 (0, or '\0,
    or false, or 0L or (1-1), or...) has magic properties. NULL has
    at least these magic properties, since it is required (by the
    standard) to expand to an integral constant expression
    evaluating to 0. It may have additional magic properties: a
    good compiler might define it to something like __builtin__null,
    and warn when it is used for something other than a pointer.

    At the project level, decide whether you (as a group) want to
    use 0 for pointers, or prefer NULL. Then stick to that
    decision.

    --
    James Kanze
     
    James Kanze, Mar 22, 2011
    #5
  6. Alf P. Steinbach /Usenet

    James Kanze Guest

    On Mar 21, 3:21 pm, Leigh Johnston <> wrote:
    > On 21/03/2011 15:08, Ruben Safir wrote:
    > > On Sun, 20 Mar 2011 11:50:49 -0400, Victor Bazarov wrote:


    > >> On 3/20/2011 11:37 AM, Ruben Safir wrote:
    > >>> On Sun, 20 Mar 2011 10:17:04 +0100, Alf P. Steinbach /Usenet wrote:


    > >>>>> template<class unk>
    > >>>>> inline unk NODE<unk>::value(){
    > >>>>> if(this)
    > >>>>> return _value;
    > >>>>> else{
    > >>>>> return 0;
    > >>>>> }
    > >>>>> }


    > >>>> 'this' is never zero.


    > >>> It can be and has been when the LIST constructor initiates a NODE
    > >>> instance as 0.


    > >> No, it cannot be null without invoking undefined behaviour first.
    > >> Calling a non-static member function using a null pointer has undefined
    > >> behaviour.


    > >>> Then as you walk down the nodes through the list, the final _next is
    > >>> always 0 and this for the _next node is 0x0, according to GDB.


    > > I don't know enough about the specs to comment but Stroustup wrote, andI
    > > just quoted this before
    > > ~~~~~~~~~~~


    > > 5.1.1


    > > Zero(0) is an int. Because the standard conversions (§C.6.2.3), 0 can be
    > > used as a constant of any integral(§4.1.1), floating point, pointer or
    > > pointer-to-member type. The type of zero will be determined by context/
    > > Zero will typically (but not necessarily) be represented by the bit
    > > pattern of all zeros for the appropriate size.


    > > No object is allocated with the address 0. Consequently, 0 acts as a
    > > pointer literal, indicating that a pointer doesn't refer to an object.


    > Just because the null pointer constant is 0 doesn't mean that the null
    > pointer value is also 0; on some implementations/platforms 0 might be a
    > valid address.


    I think I agree with what you're saying, but it's not really
    clear. 0 is an int. Period. It's never a pointer. And it's
    never an address, valid or not. A constant 0 can be converted
    to a pointer, and the results of that conversion are guaranteed
    not to point to any valid C++ object. The results of that
    conversion do not necessarily have all bits 0 (which I think is
    what you mean by a pointer having a value of 0). More
    importantly, this magic only applies to constant expressions.
    If you have an int variable, assign 0 to it, and then
    reinterpret_cast it to a pointer, the results may not be the
    same as when you assign 0 directly to the pointer.

    --
    James Kanze
     
    James Kanze, Mar 22, 2011
    #6
  7. Alf P. Steinbach /Usenet

    Noah Roberts Guest

    On 3/21/2011 7:24 PM, Ruben Safir wrote:
    > On Mon, 21 Mar 2011 10:51:26 -0700, Noah Roberts wrote:
    >
    >> On 3/21/2011 10:01 AM, Ruben Safir wrote:
    >>> On Sun, 20 Mar 2011 13:53:17 +0000, Leigh Johnston wrote:
    >>>
    >>>> On 20/03/2011 09:17, Alf P. Steinbach /Usenet wrote:
    >>>>> * Ruben Safir, on 20.03.2011 06:37:
    >>>>>> inline unk value();
    >>>>>
    >>>>> It's not necessary to designate the method as 'inline', since it's in
    >>>>> a template.
    >>>>>
    >>>>> On the other hand you should have a 'const' at the end there.
    >>>>>
    >>>>>
    >>>>>> inline unk& value_ref();
    >>>>>> inline void value(unk);
    >>>>>
    >>>>> When you have exposed a member in all ways possible, and that's
    >>>>> roughly what you have done here, what's the point of having that
    >>>>> member non-'private'?
    >>>>>
    >>>>> In this case, nothing.
    >>>>>
    >>>>> Remove the accessor and modifier stuff. Just make that value
    >>>>> 'public'.
    >>>>>
    >>>>>
    >>>> I disagree; instead I would do:
    >>>>
    >>>> const unk& value() const;
    >>>> unk& value();
    >>>> void set_value(const unk&);
    >>>>
    >>>> /Leigh
    >>>
    >>> If I define value() as a const returning a const reference, then I
    >>> can't change the value when using the operator[] and I'd think defeats
    >>> the purpose of making it a reference in the first place ..
    >>>
    >>> mylist[2] = mylust[3];
    >>>
    >>> I broke value() into two different methods, one returning the reference
    >>>
    >>> unk Node::value() const{
    >>> return value_;
    >>> }
    >>>
    >>> unk& Node::value_ref(){
    >>> return value_;
    >>> }

    >>
    >> In case you are not aware, you can override based on const-ness. For
    >> example:
    >>
    >> unk Node::value() const { return value_; } unk& Node::value() { return
    >> value_; }

    >
    > In that case, if the varibable being returned to is not const, then it
    > uses the non-const version?


    No, that's not how it works. You're not overloading on the return type.
    The return of const/non-const versions of the same function can be
    utterly unrelated, as they are in the code I showed above.

    The overload is specifically on whether or not the object who's member
    is being accessed is const or not. Generally this is what you want since:

    unk k = node.value();

    works whether value() returns a reference or value. The important part
    is, generally, whether or not the node part itself should be alterable.

    --
    http://crazycpp.wordpress.com
     
    Noah Roberts, Mar 22, 2011
    #7
  8. Alf P. Steinbach /Usenet

    James Kanze Guest

    On Mar 22, 2:54 am, Ruben Safir <> wrote:

    [...]
    > > I think I agree with what you're saying, but it's not really clear. 0
    > > is an int. Period. It's never a pointer. And it's never an address,
    > > valid or not. A constant 0 can be converted to a pointer, and the
    > > results of that conversion are guaranteed not to point to any valid C++
    > > object. The results of that conversion do not necessarily have all bits
    > > 0 (which I think is what you mean by a pointer having a value of 0).
    > > More importantly, this magic only applies to constant expressions. If
    > > you have an int variable, assign 0 to it, and then reinterpret_cast it
    > > to a pointer, the results may not be the same as when you assign 0
    > > directly to the pointer.


    > so if(ptr) is essentially no guaranteed?


    What makes you say that? Whether if(ptr) works or not depends
    on whether there is an implicit conversion to bool, and how that
    it defined. As it happens, there is: the implicit conversion
    pointer to bool is defined as the results of (pointer != 0).
    Where 0 is a null pointer constant, which will implicitly be
    converted to a null pointer of the correct type. Obviously,
    all those implicit conversions in there doesn't make the code
    very readable, and a programmer who is concerned with
    readability and maintainability will avoid such constructs, but
    for historic reasons, they're perfectly legal and well defined.
    (When bool was introduced into the language, there was a
    proposal to eliminate them, or at least deprecate them, but it
    didn't pass---there was, and still is, just too much existing
    code which uses them.)

    --
    James Kanze
     
    James Kanze, Mar 26, 2011
    #8
    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. Bob

    Problem with nulls

    Bob, Jul 2, 2003, in forum: ASP .Net
    Replies:
    0
    Views:
    336
  2. JKop
    Replies:
    3
    Views:
    505
  3. recover
    Replies:
    2
    Views:
    845
    recover
    Jul 25, 2006
  4. Paul
    Replies:
    15
    Views:
    431
    James Kanze
    Mar 28, 2011
  5. cczona
    Replies:
    1
    Views:
    125
    Rick DeNatale
    Mar 26, 2010
Loading...

Share This Page