Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. C#
  4. C# versus C++, null references and protecting against them

C# versus C++, null references and protecting against them

Scheduled Pinned Locked Moved C#
csharpc++
23 Posts 6 Posters 0 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • B bob16972

    (NOTE: I've been programming for over 20 years so please be gentle if I'm just missing something right under my nose) ;P In C++, it was common to have situations where a method definition would need something like...

    void CSomeClass::DoSomething(CAnotherClass* pObject)
    {
    /*
    For public and protected methods, it was pretty much
    a rule of thumb to check the pointer before you used it.

    For private methods, sometimes an ASSERT was enough if
    the implementation was reasonably tight but you really
    needed to approach these on a per basis.
    \*/
    
    // Maybe place an ASSERT here as well in addition to the runtime check
    if (pObject) {
    	// Do stuff with pObject
    }
    

    }

    You could simplify your world by defining the method so that it took a reference to an object...

    void CSomeClass::DoSomething(CAnotherClass& object)
    {
    /*
    No need to check the reference before using it
    since references cannot be null.
    */

    // Do stuff with object
    

    }

    Passing in a reference to an object eliminated the need to put ASSERT statements and/or runtime checks in a ton of locations that would have required it such as when using pointers. I'm finding that with C#, similar designs using reference types are requiring asserts and runtime checks all over the frackin' place. X| Someone please tell me there is a way to eliminate all these checks for null references in C# like I could in C++.

    P Offline
    P Offline
    Pete OHanlon
    wrote on last edited by
    #2

    You can either require all parameters to be passed in by ref, which is not too good a practice, or you could use something like Code Contracts to ensure it's not null.

    I'm not a stalker, I just know things. Oh by the way, you're out of milk.

    Forgive your enemies - it messes with their heads

    My blog | My articles | MoXAML PowerToys | Onyx

    B 2 Replies Last reply
    0
    • B bob16972

      (NOTE: I've been programming for over 20 years so please be gentle if I'm just missing something right under my nose) ;P In C++, it was common to have situations where a method definition would need something like...

      void CSomeClass::DoSomething(CAnotherClass* pObject)
      {
      /*
      For public and protected methods, it was pretty much
      a rule of thumb to check the pointer before you used it.

      For private methods, sometimes an ASSERT was enough if
      the implementation was reasonably tight but you really
      needed to approach these on a per basis.
      \*/
      
      // Maybe place an ASSERT here as well in addition to the runtime check
      if (pObject) {
      	// Do stuff with pObject
      }
      

      }

      You could simplify your world by defining the method so that it took a reference to an object...

      void CSomeClass::DoSomething(CAnotherClass& object)
      {
      /*
      No need to check the reference before using it
      since references cannot be null.
      */

      // Do stuff with object
      

      }

      Passing in a reference to an object eliminated the need to put ASSERT statements and/or runtime checks in a ton of locations that would have required it such as when using pointers. I'm finding that with C#, similar designs using reference types are requiring asserts and runtime checks all over the frackin' place. X| Someone please tell me there is a way to eliminate all these checks for null references in C# like I could in C++.

      J Offline
      J Offline
      jschell
      wrote on last edited by
      #3

      bob16972 wrote:

      are requiring asserts and runtime checks all over the frackin' place

      I suppose that depends on what you mean by "all over the ...place" and what exactly your intent is. In C++ I put parameter validation checks in public API methods. In C# I put parameter validation checks in public API methods. In either I might put some validation checks in other locations, but rarely do. The API would decide what sort of parameters are needed - not whether I need to check it or not. Especially since in C++ it is possible to pass a reference to a pointer. Your example code however doesn't suggest a parameter validation check but rather optional behavior it the parameter is null. That of course must be dealt with regardless. Finally null pointer exceptions in C# have stack traces on them. So arbitrary programming errors show up that way. Especially with sufficient unit testing.

      B 1 Reply Last reply
      0
      • P Pete OHanlon

        You can either require all parameters to be passed in by ref, which is not too good a practice, or you could use something like Code Contracts to ensure it's not null.

        I'm not a stalker, I just know things. Oh by the way, you're out of milk.

        Forgive your enemies - it messes with their heads

        My blog | My articles | MoXAML PowerToys | Onyx

        B Offline
        B Offline
        bob16972
        wrote on last edited by
        #4

        ref to a reference type is too much like a pointer to a pointer. However, this brings up a question I've had while trying to use C# on occasion for small projects to learn it. Are there equivalent const rules in C# (as acompared to C++) to help prevent the method from modifying the "pointer"? If there were something like that, ref might not be so bad since it would be a performance increase (at least in theory since I wouldn't need the runtime checks on the reference.

        Pete O'Hanlon wrote:

        which is not too good a practice

        My knee-jerk reaction is to agree but if it would save the runtime checks, I'd be game to study the idea more. None of my books really get into ref with reference types too much except the usual drive-by introduction. The best I've found is Richter's book but he basically says it's like a pointer to a pointer so I'm back to looking for a const solution like I would in C++. I'm not sure, but it seems const isn't really as much of a "thing" like it is in the C++ world. I'm not familiar with "Code Contracts" so I'll give it some research time. thanks.

        P 1 Reply Last reply
        0
        • J jschell

          bob16972 wrote:

          are requiring asserts and runtime checks all over the frackin' place

          I suppose that depends on what you mean by "all over the ...place" and what exactly your intent is. In C++ I put parameter validation checks in public API methods. In C# I put parameter validation checks in public API methods. In either I might put some validation checks in other locations, but rarely do. The API would decide what sort of parameters are needed - not whether I need to check it or not. Especially since in C++ it is possible to pass a reference to a pointer. Your example code however doesn't suggest a parameter validation check but rather optional behavior it the parameter is null. That of course must be dealt with regardless. Finally null pointer exceptions in C# have stack traces on them. So arbitrary programming errors show up that way. Especially with sufficient unit testing.

          B Offline
          B Offline
          bob16972
          wrote on last edited by
          #5

          jschell wrote:

          I suppose that depends on what you mean by "all over the ...place" and what exactly your intent is.

          All over the place meaning, I use objects (all over the place) which require references which can be null. Any internal, public, protected methods can be called by code that does not necessarily know my assertions inside the method. Because of this, all references that could be null need to be checked (private methods can sometimes omit this as I stated) before they are used (unless it's just passing through of course).

          jschell wrote:

          In either I might put some validation checks in other locations, but rarely do.

          Good luck with that.

          jschell wrote:

          Finally null pointer exceptions in C# have stack traces on them. So arbitrary programming errors show up that way. Especially with sufficient unit testing.

          That's assuming your debug sessions will take a particular code path; unit tests can get stale as code changes. Since this might not be reliable, the runtime checks are usually the last stand to prevent runtime errors and replace them with graceful hickups or alternative behavior. This coding style is MFC 101 and can be applied where ever pointers are sold. Since the C# references can be null, this approach almost appears mandatory but that is the question at hand.

          J 1 Reply Last reply
          0
          • P Pete OHanlon

            You can either require all parameters to be passed in by ref, which is not too good a practice, or you could use something like Code Contracts to ensure it's not null.

            I'm not a stalker, I just know things. Oh by the way, you're out of milk.

            Forgive your enemies - it messes with their heads

            My blog | My articles | MoXAML PowerToys | Onyx

            B Offline
            B Offline
            bob16972
            wrote on last edited by
            #6

            oo ouch. Design by contract... "When using contracts, a supplier should not try to verify that the contract conditions are satisfied; the general idea is that code should "fail hard"" :| Hmmm. To be fair, I guess I use this everyday (in an indirect way) now that I think about it since most class libraries seem to conform to this (at least the "fail hard" part). However, I don't think that would work well for me and my pieces of the puzzle since not catching an exception will most likely result in the same behavior as a runtime error. I tend to feel exceptions are over used anymore but I try to keep an open mind about that subject.

            1 Reply Last reply
            0
            • B bob16972

              ref to a reference type is too much like a pointer to a pointer. However, this brings up a question I've had while trying to use C# on occasion for small projects to learn it. Are there equivalent const rules in C# (as acompared to C++) to help prevent the method from modifying the "pointer"? If there were something like that, ref might not be so bad since it would be a performance increase (at least in theory since I wouldn't need the runtime checks on the reference.

              Pete O'Hanlon wrote:

              which is not too good a practice

              My knee-jerk reaction is to agree but if it would save the runtime checks, I'd be game to study the idea more. None of my books really get into ref with reference types too much except the usual drive-by introduction. The best I've found is Richter's book but he basically says it's like a pointer to a pointer so I'm back to looking for a const solution like I would in C++. I'm not sure, but it seems const isn't really as much of a "thing" like it is in the C++ world. I'm not familiar with "Code Contracts" so I'll give it some research time. thanks.

              P Offline
              P Offline
              Pete OHanlon
              wrote on last edited by
              #7

              bob16972 wrote:

              Are there equivalent const rules in C# (as acompared to C++) to help prevent the method from modifying the "pointer"

              No. This has been one of the features I've bemoaned the absence of the most.

              I'm not a stalker, I just know things. Oh by the way, you're out of milk.

              Forgive your enemies - it messes with their heads

              My blog | My articles | MoXAML PowerToys | Onyx

              1 Reply Last reply
              0
              • B bob16972

                (NOTE: I've been programming for over 20 years so please be gentle if I'm just missing something right under my nose) ;P In C++, it was common to have situations where a method definition would need something like...

                void CSomeClass::DoSomething(CAnotherClass* pObject)
                {
                /*
                For public and protected methods, it was pretty much
                a rule of thumb to check the pointer before you used it.

                For private methods, sometimes an ASSERT was enough if
                the implementation was reasonably tight but you really
                needed to approach these on a per basis.
                \*/
                
                // Maybe place an ASSERT here as well in addition to the runtime check
                if (pObject) {
                	// Do stuff with pObject
                }
                

                }

                You could simplify your world by defining the method so that it took a reference to an object...

                void CSomeClass::DoSomething(CAnotherClass& object)
                {
                /*
                No need to check the reference before using it
                since references cannot be null.
                */

                // Do stuff with object
                

                }

                Passing in a reference to an object eliminated the need to put ASSERT statements and/or runtime checks in a ton of locations that would have required it such as when using pointers. I'm finding that with C#, similar designs using reference types are requiring asserts and runtime checks all over the frackin' place. X| Someone please tell me there is a way to eliminate all these checks for null references in C# like I could in C++.

                P Offline
                P Offline
                Paul Michalik
                wrote on last edited by
                #8

                bob16972 wrote:

                Someone please tell me there is a way to eliminate all these checks for null references in C# like I could in C++.

                Hm, there is nothing like "null reference" in a C++ program. This would require dereferencing a null-pointer which immediately results in undefined behaviour of the rest of the program. If you pass an object by reference in C++, you implicitly state that this object cannot be a reference to null object by definition. In managed code you can use explicit code contracts. CCs allow you to make explicit assumptions about pre-, post- or state-conditions which are verifiable at compile- and run-time. You formulate contracts at metadata level so they get injected into IL in AOP manner:

                [ContractClass(typeof(ISomethingContract))]
                public interface ISomething {
                public void DoSomething(AnotherClass pObject);
                }

                [ContractClassFor(typeof(ISomething))]
                internal abstract class SomethingContract : ISomething {
                public void DoSomething(AnotherClass pObject) {
                Contract.Requires(pObject != null);
                }
                }
                }

                1 Reply Last reply
                0
                • B bob16972

                  (NOTE: I've been programming for over 20 years so please be gentle if I'm just missing something right under my nose) ;P In C++, it was common to have situations where a method definition would need something like...

                  void CSomeClass::DoSomething(CAnotherClass* pObject)
                  {
                  /*
                  For public and protected methods, it was pretty much
                  a rule of thumb to check the pointer before you used it.

                  For private methods, sometimes an ASSERT was enough if
                  the implementation was reasonably tight but you really
                  needed to approach these on a per basis.
                  \*/
                  
                  // Maybe place an ASSERT here as well in addition to the runtime check
                  if (pObject) {
                  	// Do stuff with pObject
                  }
                  

                  }

                  You could simplify your world by defining the method so that it took a reference to an object...

                  void CSomeClass::DoSomething(CAnotherClass& object)
                  {
                  /*
                  No need to check the reference before using it
                  since references cannot be null.
                  */

                  // Do stuff with object
                  

                  }

                  Passing in a reference to an object eliminated the need to put ASSERT statements and/or runtime checks in a ton of locations that would have required it such as when using pointers. I'm finding that with C#, similar designs using reference types are requiring asserts and runtime checks all over the frackin' place. X| Someone please tell me there is a way to eliminate all these checks for null references in C# like I could in C++.

                  P Offline
                  P Offline
                  PIEBALDconsult
                  wrote on last edited by
                  #9

                  That's because C++ references are syntactic sugar to make C++ easier for VB developers who wander over. :-D :-D

                  B 1 Reply Last reply
                  0
                  • P PIEBALDconsult

                    That's because C++ references are syntactic sugar to make C++ easier for VB developers who wander over. :-D :-D

                    B Offline
                    B Offline
                    bob16972
                    wrote on last edited by
                    #10

                    Hey now. I like C++ references and I despise VB with a passion. ;P

                    1 Reply Last reply
                    0
                    • B bob16972

                      jschell wrote:

                      I suppose that depends on what you mean by "all over the ...place" and what exactly your intent is.

                      All over the place meaning, I use objects (all over the place) which require references which can be null. Any internal, public, protected methods can be called by code that does not necessarily know my assertions inside the method. Because of this, all references that could be null need to be checked (private methods can sometimes omit this as I stated) before they are used (unless it's just passing through of course).

                      jschell wrote:

                      In either I might put some validation checks in other locations, but rarely do.

                      Good luck with that.

                      jschell wrote:

                      Finally null pointer exceptions in C# have stack traces on them. So arbitrary programming errors show up that way. Especially with sufficient unit testing.

                      That's assuming your debug sessions will take a particular code path; unit tests can get stale as code changes. Since this might not be reliable, the runtime checks are usually the last stand to prevent runtime errors and replace them with graceful hickups or alternative behavior. This coding style is MFC 101 and can be applied where ever pointers are sold. Since the C# references can be null, this approach almost appears mandatory but that is the question at hand.

                      J Offline
                      J Offline
                      jschell
                      wrote on last edited by
                      #11

                      bob16972 wrote:

                      Good luck with that.

                      Been programming 40 years myself. And my delivered software tends to have much lower bug counts compared to peers. It has nothing to do with luck and everything to do with attention to detail. Assertions "all over the place" would not help with that. Should note as well that I can't recall the last time I had to deal with a null pointer reference in my code. I can however remember dealing with them in other peoples code.

                      bob16972 wrote:

                      That's assuming your debug sessions will take a particular code path

                      Code coverage tools. Great investment.

                      bob16972 wrote:

                      unit tests can get stale as code changes.

                      That is a process problem not a technology problem. And the unit tests on the code that I maintain do not get stale.

                      bob16972 wrote:

                      Since this might not be reliable, the runtime checks are usually the last stand to prevent runtime errors and replace them with graceful hickups or alternative behavior.

                      The behavior of asserts do not fall into that categorization. You can write a class easily in C# and C++ for that matter that provides a rudimentary Aspect programming context for checking a modest number rules including null pointers.

                      bob16972 wrote:

                      This coding style is MFC 101 and can be applied where ever pointers are sold.

                      Pointer bugs which occur in C++ do not apply to C# (nor to java for that matter). A system OS exception is only one possibility that might occur due to a C++ pointer bug and is actually one of the easiest to locate and fix. Other than that having written C++ for 20 years I got by quite comfortably without scattering asserts all over my code - and again with a much lower bug rate for my code base that others.

                      bob16972 wrote:

                      Since the C# references can be null, this approach almost appears mandatory but that is the question at hand.

                      And perhaps you would be better off with an Aspect type language. A quick google suggests that that exists in some form for C# from different sources. Java has AspectJ which is a full Aspect language. Something similar might exist for C#.

                      1 Reply Last reply
                      0
                      • B bob16972

                        (NOTE: I've been programming for over 20 years so please be gentle if I'm just missing something right under my nose) ;P In C++, it was common to have situations where a method definition would need something like...

                        void CSomeClass::DoSomething(CAnotherClass* pObject)
                        {
                        /*
                        For public and protected methods, it was pretty much
                        a rule of thumb to check the pointer before you used it.

                        For private methods, sometimes an ASSERT was enough if
                        the implementation was reasonably tight but you really
                        needed to approach these on a per basis.
                        \*/
                        
                        // Maybe place an ASSERT here as well in addition to the runtime check
                        if (pObject) {
                        	// Do stuff with pObject
                        }
                        

                        }

                        You could simplify your world by defining the method so that it took a reference to an object...

                        void CSomeClass::DoSomething(CAnotherClass& object)
                        {
                        /*
                        No need to check the reference before using it
                        since references cannot be null.
                        */

                        // Do stuff with object
                        

                        }

                        Passing in a reference to an object eliminated the need to put ASSERT statements and/or runtime checks in a ton of locations that would have required it such as when using pointers. I'm finding that with C#, similar designs using reference types are requiring asserts and runtime checks all over the frackin' place. X| Someone please tell me there is a way to eliminate all these checks for null references in C# like I could in C++.

                        C Offline
                        C Offline
                        Chuck OToole
                        wrote on last edited by
                        #12

                        Hi. I don't think that passing as a reference really gets rid of the need for null checks. You can satisfy the rule for an actual object by dereferencing a pointer. That satisfies the compiler but the pointer could still be NULL. Consider this working C++ code.

                        void NameList::Append(NameList *ToBeAdded)
                        {
                        Members->Append(*ToBeAdded->Members);
                        ToBeAdded->Members->RemoveAll();
                        }

                        where "Members" is defined as

                        CObArray *Members

                        and the CObArray member Append is defined as

                        INT_PTR Append(const CObArray& src);

                        so if the "ToBeAdded" Namelist Object has a Members field that contains NULL, the compiler is OK with that and the Append function should really do ASSERT and/or runtime checks. In any event, I don't think you can rely on the & to protect against somebody passing NULL. Chuck (45 years coding and counting)

                        B 1 Reply Last reply
                        0
                        • C Chuck OToole

                          Hi. I don't think that passing as a reference really gets rid of the need for null checks. You can satisfy the rule for an actual object by dereferencing a pointer. That satisfies the compiler but the pointer could still be NULL. Consider this working C++ code.

                          void NameList::Append(NameList *ToBeAdded)
                          {
                          Members->Append(*ToBeAdded->Members);
                          ToBeAdded->Members->RemoveAll();
                          }

                          where "Members" is defined as

                          CObArray *Members

                          and the CObArray member Append is defined as

                          INT_PTR Append(const CObArray& src);

                          so if the "ToBeAdded" Namelist Object has a Members field that contains NULL, the compiler is OK with that and the Append function should really do ASSERT and/or runtime checks. In any event, I don't think you can rely on the & to protect against somebody passing NULL. Chuck (45 years coding and counting)

                          B Offline
                          B Offline
                          bob16972
                          wrote on last edited by
                          #13

                          Are you referring to what is described in the C++ Specification, Section 8.3.3, page 179 ? "A reference shall be initialized to refer to a valid object or function. [ Note: in particular, a null reference cannot exist in a well-defined program, because the only way to create such a reference would be to bind it to the “object” obtained by dereferencing a null pointer, which causes undefined behavior. As described in 9.6, a reference cannot be bound directly to a bit-field. —end note ]" Your point is taken but I think in the case you described, the violation occurs by the caller and before the prolog of the method completes. If the caller violates the standard definition of a reference, there is nothing I can do about it. I'm not even sure there is a way to check the reference for validity since the result of the action you described would be undefined (or at least, so it seems).

                          C P 2 Replies Last reply
                          0
                          • B bob16972

                            Are you referring to what is described in the C++ Specification, Section 8.3.3, page 179 ? "A reference shall be initialized to refer to a valid object or function. [ Note: in particular, a null reference cannot exist in a well-defined program, because the only way to create such a reference would be to bind it to the “object” obtained by dereferencing a null pointer, which causes undefined behavior. As described in 9.6, a reference cannot be bound directly to a bit-field. —end note ]" Your point is taken but I think in the case you described, the violation occurs by the caller and before the prolog of the method completes. If the caller violates the standard definition of a reference, there is nothing I can do about it. I'm not even sure there is a way to check the reference for validity since the result of the action you described would be undefined (or at least, so it seems).

                            C Offline
                            C Offline
                            Chuck OToole
                            wrote on last edited by
                            #14

                            Well, I was simply reacting to your statement in the original post,

                            /*
                            No need to check the reference before using it
                            since references cannot be null.
                            */

                            In my experience, when some code assumes things cannot be null, that's exactly where to start looking for bugs. And if you're assuming that a "by reference" specification removes some level of bug enough that you can remove the ASSERT / checks, then I wanted to show an example (real, not concocted) that shows the assumption to be false. And then you asked for a way to eliminate such checks from C# code like you could from C++ code, which I infer to mean that you have such checks, find them somewhat inefficient and/or redundant in well behaved programs, and would like to remove them using some help from the language. Again, I wanted to point out that the C++ language does not give you any help either and that your trust in it was misplaced. Now your reply says

                            bob16972 wrote:

                            the violation occurs by the caller and before the prolog of the method completes. If the caller violates the standard definition of a reference, there is nothing I can do about it. I'm not even sure there is a way to check the reference for validity since the result of the action you described would be undefined (or at least, so it seems).

                            which seems like an reasonable argument to remove all checks anyway since there's nothing you can do when the caller violates some rules, including the assumed rule that they'll pass something reasonable. Look, all I'm saying is that if you are writing public API entries, for other programmers to call, you're better off including the checks all the time. Yes, "null pointers" are just one element in the set of all possible bad arguments and checking for them will never catch the case of the pointer being 0x00000001 or 0xcdcdcdcd (assuming 32-bit pointers) but ASSERTs may catch enough during debugging that may make debugging easier.

                            B 1 Reply Last reply
                            0
                            • B bob16972

                              Are you referring to what is described in the C++ Specification, Section 8.3.3, page 179 ? "A reference shall be initialized to refer to a valid object or function. [ Note: in particular, a null reference cannot exist in a well-defined program, because the only way to create such a reference would be to bind it to the “object” obtained by dereferencing a null pointer, which causes undefined behavior. As described in 9.6, a reference cannot be bound directly to a bit-field. —end note ]" Your point is taken but I think in the case you described, the violation occurs by the caller and before the prolog of the method completes. If the caller violates the standard definition of a reference, there is nothing I can do about it. I'm not even sure there is a way to check the reference for validity since the result of the action you described would be undefined (or at least, so it seems).

                              P Offline
                              P Offline
                              Paul Michalik
                              wrote on last edited by
                              #15

                              bob16972 wrote:

                              If the caller violates the standard definition of a reference, there is nothing I can do about it. I'm not even sure there is a way to check the reference for validity since the result of the action you described would be undefined (or at least, so it seems).

                              Exactly, with no need to further qualify the statement as you did in the second sentence. And no, there is no way to check a reference for validity, since it must be valid by definition. Otherwise, the caller has violated (a) the language specification of a valid C++ program and (b) the contract you have specified by defining the method signature that way... That's what I wrote in my post above (which was down-voted for some reason).

                              B 1 Reply Last reply
                              0
                              • P Paul Michalik

                                bob16972 wrote:

                                If the caller violates the standard definition of a reference, there is nothing I can do about it. I'm not even sure there is a way to check the reference for validity since the result of the action you described would be undefined (or at least, so it seems).

                                Exactly, with no need to further qualify the statement as you did in the second sentence. And no, there is no way to check a reference for validity, since it must be valid by definition. Otherwise, the caller has violated (a) the language specification of a valid C++ program and (b) the contract you have specified by defining the method signature that way... That's what I wrote in my post above (which was down-voted for some reason).

                                B Offline
                                B Offline
                                bob16972
                                wrote on last edited by
                                #16

                                Jeez. You missed the whole point of what I'm trying to do. You keep focusing on C++ references and pointers whereas I have no problem with C++ since I can choose to use pointers when I want to allow null and a reference when I don't. In C# sharp, I don't seem to have that option (except for ref apparently which would require a const to (attempt to) protect the caller from the method changing the reference on them. From reading your earlier post, you apparently didn't read the code comments in my code examples as I had already stated that a reference can't be null but you tried to explain that very thing to me which would indicate you missed the point and the question. Regardless, I appreciate your attempt to help find a solution, for what it's worth. thanks.

                                1 Reply Last reply
                                0
                                • C Chuck OToole

                                  Well, I was simply reacting to your statement in the original post,

                                  /*
                                  No need to check the reference before using it
                                  since references cannot be null.
                                  */

                                  In my experience, when some code assumes things cannot be null, that's exactly where to start looking for bugs. And if you're assuming that a "by reference" specification removes some level of bug enough that you can remove the ASSERT / checks, then I wanted to show an example (real, not concocted) that shows the assumption to be false. And then you asked for a way to eliminate such checks from C# code like you could from C++ code, which I infer to mean that you have such checks, find them somewhat inefficient and/or redundant in well behaved programs, and would like to remove them using some help from the language. Again, I wanted to point out that the C++ language does not give you any help either and that your trust in it was misplaced. Now your reply says

                                  bob16972 wrote:

                                  the violation occurs by the caller and before the prolog of the method completes. If the caller violates the standard definition of a reference, there is nothing I can do about it. I'm not even sure there is a way to check the reference for validity since the result of the action you described would be undefined (or at least, so it seems).

                                  which seems like an reasonable argument to remove all checks anyway since there's nothing you can do when the caller violates some rules, including the assumed rule that they'll pass something reasonable. Look, all I'm saying is that if you are writing public API entries, for other programmers to call, you're better off including the checks all the time. Yes, "null pointers" are just one element in the set of all possible bad arguments and checking for them will never catch the case of the pointer being 0x00000001 or 0xcdcdcdcd (assuming 32-bit pointers) but ASSERTs may catch enough during debugging that may make debugging easier.

                                  B Offline
                                  B Offline
                                  bob16972
                                  wrote on last edited by
                                  #17

                                  I agree that if a legal value can be null, always check it first. However, for a C++ reference, the rules don't provide for a legal null value so its not a valid option for the caller. In C++, by definition, you cannot have a null reference. If the caller tries to do anything that dereferences a null pointer, they have violated the rules and will probably crash the program before the function or method call. What you are proposing is that I can somehow protect against the caller crashing the program before they even enter the method or function. Think about it. your suggesting the caller can access memory location NULL, which for sake of argument is 0 in MFC, which results in an attempt to get the value at virtual memory location 0. In windows, attempting access any virtual memory address between 0-65535 will cause a violation. My function or method would not even be involved at that point so I would hope you would grant that there is no need to protect against something that can never get past the threshold of my functions prologue. If you won't grant me that argument, then I'd be interested to hear the rebuttal as I don't see how it could get into my function in the first place before being stuffed by the OS. Regardless, thanks for the comments as they have been thought provoking and interesting and always welcome.

                                  C 1 Reply Last reply
                                  0
                                  • B bob16972

                                    I agree that if a legal value can be null, always check it first. However, for a C++ reference, the rules don't provide for a legal null value so its not a valid option for the caller. In C++, by definition, you cannot have a null reference. If the caller tries to do anything that dereferences a null pointer, they have violated the rules and will probably crash the program before the function or method call. What you are proposing is that I can somehow protect against the caller crashing the program before they even enter the method or function. Think about it. your suggesting the caller can access memory location NULL, which for sake of argument is 0 in MFC, which results in an attempt to get the value at virtual memory location 0. In windows, attempting access any virtual memory address between 0-65535 will cause a violation. My function or method would not even be involved at that point so I would hope you would grant that there is no need to protect against something that can never get past the threshold of my functions prologue. If you won't grant me that argument, then I'd be interested to hear the rebuttal as I don't see how it could get into my function in the first place before being stuffed by the OS. Regardless, thanks for the comments as they have been thought provoking and interesting and always welcome.

                                    C Offline
                                    C Offline
                                    Chuck OToole
                                    wrote on last edited by
                                    #18

                                    I'm afraid you missed a subtle point in my example, the point that gets you into your function with a NULL value. I've simplified it below

                                    void Bar(CObArray &ar)
                                    {
                                    int foo = ar.GetCount();
                                    }

                                    void Foo(void)
                                    {
                                    CObArray *bob = NULL;

                                    Bar(\*bob);
                                    

                                    }

                                    set a breakpoint on the "int foo = ar.GetCount()" and observe that ar cannot be examined in the debugger, it's value is null. Note that you do in fact get to that statement, that is, the "Bar(*bob)" in the function "Foo" does not throw an exception. Although it looks like it is dereferencing the clearly null pointer, it's really just creating the argument for Bar by getting the address of the CObject and passing it, that is, making a "by reference" value for the Bar function. Therefore, the "crash" happens in "Bar" (i.e. your function) rather than at the invocation site. In my first reply, I was showing that the "ToBeAdded" object, which was valid, had a "Members" data member that was, in fact, NULL and that there was no "help" from the compiler / language rules that prevented it from passing NULL, even though the rules appear to say that's illegal. So, my conclusion was that if you don't want to allow NULL as an input to your functions and that you used to explicitly ASSERT / check for that case, you need to continue to check for that case because simply using "&" to eliminate that possibility was not going to work. Thus ends my rebuttal :)

                                    P B 2 Replies Last reply
                                    0
                                    • C Chuck OToole

                                      I'm afraid you missed a subtle point in my example, the point that gets you into your function with a NULL value. I've simplified it below

                                      void Bar(CObArray &ar)
                                      {
                                      int foo = ar.GetCount();
                                      }

                                      void Foo(void)
                                      {
                                      CObArray *bob = NULL;

                                      Bar(\*bob);
                                      

                                      }

                                      set a breakpoint on the "int foo = ar.GetCount()" and observe that ar cannot be examined in the debugger, it's value is null. Note that you do in fact get to that statement, that is, the "Bar(*bob)" in the function "Foo" does not throw an exception. Although it looks like it is dereferencing the clearly null pointer, it's really just creating the argument for Bar by getting the address of the CObject and passing it, that is, making a "by reference" value for the Bar function. Therefore, the "crash" happens in "Bar" (i.e. your function) rather than at the invocation site. In my first reply, I was showing that the "ToBeAdded" object, which was valid, had a "Members" data member that was, in fact, NULL and that there was no "help" from the compiler / language rules that prevented it from passing NULL, even though the rules appear to say that's illegal. So, my conclusion was that if you don't want to allow NULL as an input to your functions and that you used to explicitly ASSERT / check for that case, you need to continue to check for that case because simply using "&" to eliminate that possibility was not going to work. Thus ends my rebuttal :)

                                      P Offline
                                      P Offline
                                      Paul Michalik
                                      wrote on last edited by
                                      #19

                                      What you describe is Microsoft (implementation) specific version of "undefined behavior". The code in Foo is ill-formed and any assumptions about what happens after you took a reference to a "null" pointer are worthless...(the lang. spec. does not require an exception to be thrown.)

                                      C 2 Replies Last reply
                                      0
                                      • P Paul Michalik

                                        What you describe is Microsoft (implementation) specific version of "undefined behavior". The code in Foo is ill-formed and any assumptions about what happens after you took a reference to a "null" pointer are worthless...(the lang. spec. does not require an exception to be thrown.)

                                        C Offline
                                        C Offline
                                        Chuck OToole
                                        wrote on last edited by
                                        #20

                                        Well, that is true to some extent (the undefined behavior part, not the malformed part :)) Unfortunately, I don't live in the happy world where I can rely on everybody following the rules or where I can hold up a standard and claim it's not my fault that my code blew up. I live in a world, somewhat dominated by Microsoft whose implementation details have real effects, where my libraries, reusable modules, etc are to be used by other programmers and they will often have bugs. I try my best to prevent their bugs from crashing my code but instead give them a reasonable exception or other error indicator so they can find their own bugs without calling me to say "your code crashed". Perhaps this is ingrained in me from my early years of operating system development where a kernel crash was the worst possible thing regardless of what the "user" did to it via the APIs. Imagine how angry people would get if simple calls to the base Windows APIs would cause blue screens all the time.

                                        paul_71 wrote:

                                        any assumptions about what happens after you took a reference to a "null" pointer are worthless

                                        And this is exactly my point to the OP, his assumption that one cannot get into his code with a null object reference by using "&" is also worthless (your words) as I can clearly demonstrate that you can. In any event, I will continue to challenge the assertion that one can remove defensive code because "by definition it cannot happen".

                                        1 Reply Last reply
                                        0
                                        • P Paul Michalik

                                          What you describe is Microsoft (implementation) specific version of "undefined behavior". The code in Foo is ill-formed and any assumptions about what happens after you took a reference to a "null" pointer are worthless...(the lang. spec. does not require an exception to be thrown.)

                                          C Offline
                                          C Offline
                                          Chuck OToole
                                          wrote on last edited by
                                          #21

                                          PS, it seems they've been arguing about this exact syntax for quite some time now. it appears there are two camps in the standard, one that wants it be defined behavior and one that does. The following like should provide some interesting reading on the subject. http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#232

                                          1 Reply Last reply
                                          0
                                          Reply
                                          • Reply as topic
                                          Log in to reply
                                          • Oldest to Newest
                                          • Newest to Oldest
                                          • Most Votes


                                          • Login

                                          • Don't have an account? Register

                                          • Login or register to search.
                                          • First post
                                            Last post
                                          0
                                          • Categories
                                          • Recent
                                          • Tags
                                          • Popular
                                          • World
                                          • Users
                                          • Groups