1
  • I've heard that accessing a pointer whose value is null is safe since you are not setting any data to it or from it, you are just accessing it.

  • But I also heard that accessing what it points to (when it's null) isn't safe, why is that?

  • If you are accessing to what it points to (when it's null) aren't you accessing nothing?

  • I think that there shouldn't be any issues with that unless you are setting values to something from it.

  • I've heard that from many people tho I never experienced any crashes or bugs related to that (when reading data from inside a pointer that is null), when I catch an exception I just let it be since I'm not setting any data from it to something. Is that ok?

int x; 
int* px = &x; 
int* pn = nullptr; 
if (px==px) { do something;} 
  • 4
    Dereferencing a null pointer is undefined behavior. – Jason May 20 '22 at 05:48
  • 1
    What do you mean by "accessing"? Like reading its value (e.g. `int* ptr = nullptr; std::cout << ptr;`)? Or *dereferencing* the pointer (e.g. `int* ptr = nullptr; std::cout << *ptr;`)? – Some programmer dude May 20 '22 at 05:52
  • 2
    Also, possible crashes from invalid pointer dereference (which aren't guaranteed to happen!) aren't thrown as C++ exceptions, you can't catch them in that way. – Some programmer dude May 20 '22 at 05:53
  • 1
    Invalid pointer dereferences _might be_ thrown as exceptions, undefined behavior is undefined. – Nathan Pierson May 20 '22 at 05:54
  • 1
    @Someprogrammerdude By accessing I mean dereferencing –  May 20 '22 at 05:54
  • From [this answer](https://stackoverflow.com/a/4009070/12002570): *"Dereferencing just means accessing the memory value at a given address."* – Jason May 20 '22 at 05:54
  • 2
    In that case I don't understand what you think is the difference between "accessing a pointer whose value is null" (which you think is safe) and "accessing what it points to" (which isn't). – Nathan Pierson May 20 '22 at 05:55
  • 1
    Dereferencing a null pointer does not try to access *nothing*, it tries to access *something* that is *nowhere*. – molbdnilo May 20 '22 at 05:57
  • I think with "accessing a pointer" you mean dereferecing it, e.g. `Foo &foo = *fooPtr;` and with "accessing what it points to" you mean accessing properties of the referenced value, e.g. `std::cout << fooPtr->someMember;`? Is that right? – Lukas-T May 20 '22 at 05:57
  • @churill exactly, that is what I meant. –  May 20 '22 at 05:58
  • The "arrow" syntax is really syntactic sugar for plain dereference with the `*` operator. E.g. `fooPtr->someMember` is equivalent to `(*fooPtr).someMember`. In both cases there's a dereference, which is "accessing what it points to". And that is UB for null or otherwise invalid pointers. – Some programmer dude May 20 '22 at 06:01
  • _I've heard that accessing a pointer whose value is null is safe_ Whoever told you this doesn't know the stuff. I would check twice what this person told you else... :-) – Scheff's Cat May 20 '22 at 06:02
  • @Scheff'sCat Former System Engineer Then IT Architect at IBM (company) told me that. –  May 20 '22 at 06:03
  • @OskarKierakowicz I am pretty sure either you have misinterpreted his(architect at ibm) statement or misheard him, assuming he/she was talking about C++ in the first place. – Jason May 20 '22 at 06:04
  • Are you sure he was talking about C++? When I worked on SGI / Irix in the past, the access to null pointers wasn't valid as well (of course) but it didn't result in a crash like I was used on a PC. Guess how surprised I was when I compiled this software for PC/Linux. It already crashed before even reaching `main()`. That was a hard lesson but a valuable... ;-) – Scheff's Cat May 20 '22 at 06:06
  • @Scheff'sCat you are right, he spoke about C and not C++ my bad, Sorry. If it really causes the software/program/dll to have Undefined behavior then the conversation is over, thanks everyone. –  May 20 '22 at 06:08
  • That doesn't make a difference. To dereference a null pointer is Undefined Behavior in C as well. (I guess C++ inherited this behavior from C.) The [cppreference doc. for C](https://en.cppreference.com/w/c/language/operator_member_access) does mention it explicitly. In the [C++ doc.](https://en.cppreference.com/w/cpp/language/operator_member_access#Built-in_indirection_operator), I missed this detail somehow (or overlooked it). – Scheff's Cat May 20 '22 at 06:10
  • @molbdnilo _"access something that is nowhere."_ That's quite poetic :) – Lukas-T May 20 '22 at 06:39

2 Answers2

1

By accessing I mean dereferencing

Dereferencing a null pointer is undefined behavior.

I never experienced any crashes or bugs related to that

The program has undefined behavior meaning it is still in error even if it doesn't say so explicitly and "seems to be working".

Undefined behavior means anything1 can happen including but not limited to the program giving your expected output. But never rely(or make conclusions based) on the output of a program that has undefined behavior. The program may just crash.

So the output that you're seeing(maybe seeing) is a result of undefined behavior. And as i said don't rely on the output of a program that has UB. The program may just crash.

So the first step to make the program correct would be to remove UB. Then and only then you can start reasoning about the output of the program.


1For a more technically accurate definition of undefined behavior see this where it is mentioned that: there are no restrictions on the behavior of the program.

Jason
  • 36,170
  • 5
  • 26
  • 60
0

The sample code (as it's exposed by OP in this moment) got a bit confusing.

Thus, I would like to add some examples to the accepted answer what's allowed and what not:

#include <iostream>

int main()
{
  int x = 0; // make some storage
  int* px = &x; // px initalized with address of x     -> OK.
  int* pn = nullptr; // pn initialized with nullptr    -> OK.
  if (px == px) { /* ... */ } // senseless but         -> OK.
  if (px == pn) { /* ... */ } //                       -> OK.
  std::cout << *px; // dereference a valid pointer     -> OK.
  std::cout << *pn; // dereference a null pointer      -> UNDEFINED BEHAVIOR!
  px = pn; // assign a (null) pointer                  -> OK.
  std::cout << *px; // dereference a null pointer      -> UNDEFINED BEHAVIOR!
  // ...and finally a common bug...
  int* py = nullptr; //                                -> OK.
  { int y = 1; // storage with limited life-time       -> OK.
    py = &y; // assign address of storage              -> OK.
  } // scope end -> life-time of y ends                -> OK.
  // Attention! This makes py dangling (pointing to released storage).
  if (py /* != nullptr*/) { // This doesn't help. py is not a null pointer.
    std::cout << *py; // access after end of life-time -> UNDEFINED BEHAVIOR!
  }
}

Output of Compiler (g++ 11.2):

g++ -std=c++17 -O2 -Wall -pedantic -pthread main.cpp # && ./a.out # Compile but don't exec. It contains UNDEFINED BEHAVIOR!
main.cpp: In function 'int main()':
main.cpp:8:10: warning: self-comparison always evaluates to true [-Wtautological-compare]
    8 |   if (px == px) { /* ... */ } // senseless but         -> OK.
      |       ~~ ^~ ~~

Demo on coliru

Scheff's Cat
  • 19,528
  • 6
  • 28
  • 56