operator-> can only be overloaded as a member function of a class, not for a normal pointer.
In general there is no way to check that a (non-null) pointer actually points to a valid object. In your example delete pObj; does nothing to change the pointer; it just leaves it pointing to invalid memory, and there is no way to test for that. So, even if you could overload operator-> here, the best it could do is check that it wasn't null.
The usual approach is to use smart pointers, rather than normal pointers. A smart pointer is a class that wraps a plain pointer to an object, and has overloads of operator* and operator-> so that it looks and feels like a pointer. You won't delete the object directly, but through the pointer (when it goes out of scope, or explicitly by calling a reset() function), and the pointer can then set its plain pointer to null when that happens. In that way, the plain pointer will always be either valid, or null, so the overloaded operators can usefully check it before dereferencing.
Smart pointers (and RAII in general) bring other advantages too: automatic memory management, and exception safety. In your code, there will be a memory leak if DoStuff() throws an exception; pObj will go out of scope, and so there will be no way to access it to delete the object it points to. The memory will be lost and, if this keeps happening, you will eventually use all the system's memory and either crash or slow to a crawl. If it were a smart pointer, then the object would be deleted automatically as it went out of scope.
Commonly used smart pointers from the Standard Library and Boost are auto_ptr, scoped_ptr and shared_ptr, each with different behaviour when copying the pointer. C++0x will introduce unique_ptr to replace auto_ptr.
The amount of bugs this game has makes me want to quit this game forever. What a complete s**t show. Fix your game and hire some decent developers. Its embarrassing what I am experiencing from just a couple days of gameplay....
Also posted on the official New World forum: Link
-
The most serious bug of all if you play a healer. If you enable target-lock (with middle-mouse button) and scroll through healable targets, the game suddenly crashes with (and without) a NULLPTR message stating:
(SafePtr) - Attempting to dereference an null ptr.
It happens in every type of content (solo, party, dungeon, pvp), but is especially annoying (to the point of rage quiting) when you do world pvp with your clan, scroll through your targets and crash the game twice within 5mins of gameplay. You can test this for yourself if you go to your town (whilst not in a party) enable the target-lock, scroll through your targets, afk a bit, maybe tab out of the game, come back in, scroll again and boom, it crashes. FIX THIS ASAP!
-
Open your target-lock (with MMB) > press escape > click on game menu tab > click on submit feedback > submit the actual feedback > now the target-lock is invisible forever and you are only able to get it back if you press [ESCAPE].
-
Open your target-lock (with MMB) > perform a light attack with your staff > the target lock gets cancelled and you need to open it again. Do the same, only this time use a heavy attack instead of a light attack. You will notice that the target-lock never gets cancelled (the way it should be).
-
Hold [CONTROL] and never release it > cast a self heal > perform an attack (light or heavy) > cast a self heal immediately after > you will notice it doesn't self-heal even though you had [CONTROL] down the whole time.
-
Open your target-lock with [MMB] > lay down on the ground with [Z] > the target-lock gets cancelled and you need to open it again. Now do the same, but this time crouch with [C] instead of laying down on the ground. You will notice that the target-lock stays on (the way it should be).
-
When not in a party and you are close to a clan member > open target-lock to lock into your clan-member > you will notice that sometimes the inner health bar above his head is larger than the actual bar-element. See screenshot
-
Depending on what type of player you target-lock into it changes the target-lock's color. For example, locking into a party member shows their name + bar blue colored. Locking into a clan member shows it green color. Anything other than these two shows them white colored. When you join a party or leave a party and open the target-lock this color can be completely random (bug). Name can be green and bar can be blue, any color combination (blue, green, white) is possible.
These next ones are not healer related...
-
Party frame anchoring is a complete mess. The amount of times this element takes different shapes is beyond my level of comprehension. What a horrible piece of code that handles this. Sometimes it anchors itself more to the right, sometimes more to the bottom, sometimes there is extra spacing between every party member, sometimes the font size changes. Horrible...just horrible. You can fix this bug, by pressing escape, which hides the party frames and internally resets it. See screenshot
-
Sometimes when a popup shows up in the topright corner, it animates the questlog to the bottom. There are multiple instances where the questlog animates down and doesnt reset into its original position (topright) and keep going down while continueing playing this game with this bug. To the point where it actually overlaps where your weapon and skill icons are (bottomright).
-
Sometimes the questlog is hidden for no reason and its impossible to make it show again. After a long time the questlog reappears. Sometimes this fixes itself when you move to a new zone, but this is not always the case.
-
Gathering sometimes doesnt work. It stays locked in the gathering animation not picking up the loot after the circular bar is full (gathering bar also stays locked in full state). There were also cases where no circular bar was visible at all.
-
There are multiple instances when you [ALT-TAB] out of the game, your mouse cursor becomes invisible. The only way I found to fix this is by using [CONTROL-ALT-DELETE], moving the mouse for a couple of seconds and then it re-appears again. This only happens to me specifically with this game.
-
Multiple instances where the same achievement popup shows up again, even though I already claimed it before. This also happens when I restart the game.
-
Repairing your equipment is not possible sometimes, because the game thinks that my abilities are on cooldown, when they are not. When the bug occurs, the context menu doesnt work either. For example, you can not leftclick or rightclick the items to select salvage. Using the shortcut doesnt work either. The bug can be fixed, by un-equiping your weapon and equiping a new weapon.
-
The message popup ([F3] to fish) randomly pops up when you are not close to water (happens in town, forests etc.)
-
Sometimes when killing a wolf it doesnt let you skin it or run through it (the hitbox is bugged). This happened to me in the Bronze Grove area.
-
When you are in a party and a party member pins something on the map and that same member leaves the party, his pins on the map gets removed (which is good), but it doesnt remove his pins from the compass.
-
sometimes a common wolf in the woods is immune to any damage, until you swap weapons back and forth. Then it can receive damage again.
-
Leftclick attack sometimes get completely blocked in the game. The only way to fix this is by restarting the game. Relogging doesnt work.
-
When a german player uses emotes, it shows the emote in chat in german. Why??? I have an english client installed
-
People I have played with in a party, but are not currently in my party, can read my new party chat? WTH???
-
Press [ESCAPE] to open menu > click game menu > click recall to inn > press yes > now it starts recalling > press forward during the recall to cancel it > the menu is still open, because you never closed it > now click the game menu tab again and you will notice that this specific tab doesnt work anymore.
-
Used the role the dice emote, then went to kill a wolf and as soon as I started to skin it, it showed the roll the dice message again in chat. It also sometime spams the roll the dice emote in chat when the abandoning event popup in the top-right corner shows up.
-
When cooking sometimes a different item is crafted than the on you have selected in the menu. This occured to me with cooking travel ration food, it made light ration food instead (I was not lagging and I did double check I had the correct food selected)
-
Sometimes when you [ALT-TAB] out of the game and come back in, your character skills and weapon icons in the UI become invisible. Pressing escape fixes this bug.
-
Sometimes its impossible to change your character's title. When you go to your bio to change it, the current title is set to <Uninitialized> and the button to change the title doesnt work.
-
Sometimes when encumbered, your character starts to stutterstep like crazy and it even allows you to jump (which should not be possible when encumbered. Reducing the weight in your inventory (losing the encumbering effect) fixes this problem.
You should post this on the official forums, the devs likely don't read reddit.
How about this one? 0.07minutes... why not use a readable format like seconds? See screenshot
C++ Overload or monitor the dereference operator (on a pointer) - Stack Overflow
Error using Projection. Trying to dereference null pointer
Avoiding null ptr dereferences
A smart pointer implementation that throws when dereferencing a null pointer
operator-> can only be overloaded as a member function of a class, not for a normal pointer.
In general there is no way to check that a (non-null) pointer actually points to a valid object. In your example delete pObj; does nothing to change the pointer; it just leaves it pointing to invalid memory, and there is no way to test for that. So, even if you could overload operator-> here, the best it could do is check that it wasn't null.
The usual approach is to use smart pointers, rather than normal pointers. A smart pointer is a class that wraps a plain pointer to an object, and has overloads of operator* and operator-> so that it looks and feels like a pointer. You won't delete the object directly, but through the pointer (when it goes out of scope, or explicitly by calling a reset() function), and the pointer can then set its plain pointer to null when that happens. In that way, the plain pointer will always be either valid, or null, so the overloaded operators can usefully check it before dereferencing.
Smart pointers (and RAII in general) bring other advantages too: automatic memory management, and exception safety. In your code, there will be a memory leak if DoStuff() throws an exception; pObj will go out of scope, and so there will be no way to access it to delete the object it points to. The memory will be lost and, if this keeps happening, you will eventually use all the system's memory and either crash or slow to a crawl. If it were a smart pointer, then the object would be deleted automatically as it went out of scope.
Commonly used smart pointers from the Standard Library and Boost are auto_ptr, scoped_ptr and shared_ptr, each with different behaviour when copying the pointer. C++0x will introduce unique_ptr to replace auto_ptr.
You should overload operators -> and *, in more or less the same way that auto_ptr works. For example:
template<typename T>
class SafePtr {
public:
SafePtr(T*p) : ptr(p) {}
T &operator*()
{
if ( !preConditions() ) {
throw runtime_error( "preconditions not met" );
}
return *ptr;
}
T * operator->()
{
if ( !preConditions() ) {
throw runtime_error( "preconditions not met" );
}
return ptr;
}
bool preConditions()
{ return ( ptr != NULL ); }
private:
T* ptr;
};
This could be a very basic example. The -> operator would be overloaded in a similar way. All the logic you want to execute before dereferencing the pointer would be coded inside preConditions(). I think that you can get the idea from here, if not, you can ask further.
Hope this helps.
EDIT: Conclusion if you find this thread in the future:
As of 2023-april-17, Go uses the old C approach to pointer safety: "Good programmers don't write bugs," although it is thankfully a defined (runtime) error rather than UB to read from a null pointer.
The compiler will not catch it if you write a function that reads from a pointer argument without checking for null.
Edit 2:
In response to this:
You seem unproportionately angry by this
I literally didn't believe my colleague when he complained about this earlier today, that's how incredible it is.
Null pointer dereferences have been a problem since the invention of null in 1965, a known problem since 1965+1, and remedies have been known and implemented in other languages for, at this point, literally decades.
-
C gets away with having this problem because it is too old.
-
Rust can do it because you have to specifically wrap code with unchecked dereferences in an "unsafe" region.
-
Zig has two kinds of pointers specifically to express these semantics.
-
C++ - terrible old C++ where everything is a catastrophe - recognizes this and lets you implement gsl::not_null<T>.
So I actually am kind of angry, yes. Having this problem in a modern compiled language is amateur hour. Having it in a language that isn't even used for Hard Realtime is professional malpractice by the inventors.
Original post:
A colleague has a null ptr dereference in Go.
I advised him to do as I would do - working in other languages, I tend to crank the warning level high and turn warnings into errors.
In e.g. C#, that means I cannot compile this code:
private static string bad_deref(object? Object)
{
return Object.ToString();
}because I get
x.cs(y,z): [CS8602] Dereference of a possibly null reference.
Which, to be clear, is very good.
But he tells me Go doesn't have a warning level to crank and, googling, it would appear he is right.
So how do you solve this problem in Go? Are we back to good old C advice "good programmers don't make mistakes" and null ptr dereferences just sometimes happen if you don't work with perfect people?
Hi, I wrote a simple (i.e. incomplete ) implementation of a smart pointer that throws when de-referencing a null pointer. This enable you to write code like this:
template<typename T>
void foo(safe_ptr<T> & ptr1, safe_ptr<T> & ptr2) {
try {
ptr1->bar();
ptr2->baz();
} catch ( null_dereference_exception ) {
}
} http://pastebin.com/j5eZA4AK
Edit: syntax :)
Dereferencing a null pointer is Undefined Behavior.
An Undefined Behavior means anything can happen, So it is not possible to define a behavior for this.
Admittedly, I am going to add this C++ standard quote for the nth time, but seems it needs to be.
Regarding Undefined Behavior,
C++ Standard section 1.3.24 states:
Permissible undefined behavior ranges from ignoring the situation completely with unpredictable results, to behaving during translation or program execution in a documented manner characteristic of the environment (with or without the issuance of a diagnostic message), to terminating a translation or execution (with the issuance of a diagnostic message).
NOTE:
Also, just to bring it to your notice:
Using a returned reference or pointer to a local variable inside a function is also an Undefined Behavior. You should be allocating the pointer on freestore(heap) using new and then returning a reference/pointer to it.
EDIT:
As @James McNellis, appropriately points out in the comments,
If the returned pointer or reference is not used, the behavior is well defined.
When you dereference a null pointer, you don't necessarily get an exception; all that is guaranteed is that the behavior is undefined (which really means that there is no guarantee at all as to what the behavior is).
Once the *temp expression is evaluated, it is impossible to reason about the behavior of the program.
There is a concept, in the standard, of a null pointer value. This is a distinct value that causes undefined behavior when the program attempts to access memory through it. In practice, lots of modern implementations have it crash the program, which is useful behavior. After all, such an attempt is a mistake.
The name of the null pointer value is 0, or any other constant integral expression in pointer context (like 3 - 3, for example). There is also a NULL macro, which has to evaluate to 0 in C++ but can be (void *)0 in C (C++ insists more on pointers being type-safe). In C++0x, there will be an explicit value called nullptr, finally giving the null pointer an explicit name.
The value of the null pointer doesn't have to be an actual zero, although it is on all implementations I'm aware of, and the odd computers where that didn't work have mostly been retired.
You're misstating what happens in your last example. *b doesn't resolve into anything. Passing *b is undefined behavior, which means the implementation can do anything it likes with it. It may or may not be flagged as an error, and may or may not cause problems. The behavior can change for no apparent reason, and so doing this is a mistake.
If a called function is expecting a pointer value, passing it a null pointer value is perfectly legitimate, and the called function should handle it properly. Dereferencing a null pointer value is never legitimate.
Whether or not the mere fact of dereferencing a null pointer already results in undefined behavior is currently a gray zone in the Standard, unfortunately. What is certain is that reading a value out of the result of dereferencing a pointer is undefined behavior.
That it is undefined behavior is stated by various notes throughout the Standard. But notes are not normative: They could say anything, but they will never be able to state any rules. Their purpose is entirely informative.
That calling a member function on a null pointer formally is undefined behavior too.
The formal problem with merely dereferencing a null pointer is that determining the identity of the resulting lvalue expression is not possible: Each such expression that results from dereferencing a pointer must unambiguously refer to an object or a function when that expression is evaluated. If you dereference a null pointer, you don't have an object or function that this lvalue identifies. This is the argument the Standard uses to forbid null-references.
Another problem that adds to the confusion is that the semantics of the typeid operator make part of this misery well defined. It says that if it was given an lvalue that resulted from dereferencing a null pointer, the result is throwing a bad_typeid exception. Although, this is a limited area where there exist an exception (no pun) to the above problem of finding an identity. Other cases exist where similar exception to undefined behavior is made (although much less subtle and with a reference on the affected sections).
The committee discussed to solve this problem globally, by defining a kind of lvalue that does not have an object or function identity: The so called empty lvalue. That concept, however, still had problems, and they decided not to adopt it.
Now, practically, you will not encounter a crash when merely dereferencing a null pointer. The problem of identifying an object or function for an lvalue seems to be entirely language theoretical. What is problematic is when you try to read a value out of the result of dereference. The following case will almost certainly crash, because it tries to read an integer from an address which is most probably not mapped by the affected process
int a = *(int*)0;
There are few cases where reading out of such an expression probably won't cause a crash. One is when you dereference an array pointer:
int *pa = *(int(*)[1])0;
Since reading from an array just returns its address using a element pointer type, this will most probably just make a null pointer (but as you dereference a null pointer before, this still is undefined behavior formally). Another case is dereferencing of function null pointers. Here too, reading a function lvalue just give you its address but using a function pointer type:
void(*pf)() = *(void(*)())0;
Aswell as the other cases, this is undefined behavior too, of course, but will probably not result in a crash.
Like the above cases, just calling a non-virtual member function on a null pointer isn't practically problematic either, most probably - even though it formally is undefined behavior. Calling the function will jump to the functions address, and don't need to read any data. As soon as you would try to read a nonstatic data-member, the same problem occurs as when reading out of a normal null pointer. Some people place an
assert(this != NULL);
In front of some member function bodies in case they accidentally called a function on a null pointer. This may be a good idea when there are often cases where such functions are mistakenly called on null pointers, to catch errors early. But from a formal point of view, this can never be a null pointer in a member function.