5

I've been reading about the C++11 smart pointers in order to use them on my sources, the documentation I've been reading is the one on cppreference.com; while reading about the std::unique_ptr, on the reset function there's a documentation that seems incorrect to me (emphasis mine):

Replaces the managed object.

  • Given current_ptr, the pointer that was managed by *this, performs the following actions, in this order:

    1. Saves a copy of the current pointer old_ptr = current_ptr.
    2. Overwrites the current pointer with the argument current_ptr = ptr.
    3. If the old pointer was non-empty, deletes the previously managed object if(old_ptr != nullptr) get_deleter()(old_ptr).

In the C++ standard documentation, we can read the well known delete null pointer feature:

Extract from n3690 standard 5.3.5 Delete (emphasis mine):

If the value of the operand of the delete-expression is not a null pointer value, then:

— If the allocation call for the new-expression for the object to be deleted was not omitted, the delete-expression shall call a deallocation function. The value returned from the allocation call of the new-expression shall be passed as the first argument to the deallocation function.

Otherwise, the delete-expression will not call a deallocation function.

So, I'm wondering why cppreference says that the unique_ptr::reset function checks for the nullity of the managed pointer before it's deletion even while te standard says that no deallocation function would be called over a null pointer (that's why the cppreference documentation seems incorrect to me).

Is kind of obvious that I must be mistaken and there must be a reason to do things this way, but I'm unable to imagine what reason it could be. Any hints?

PS: Where in the standard is defined how the std::unique_ptr must be implemented or behave? In the 20.9.1 Class template unique_ptr I cannot found anything about the check-for-nullity stuff.

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
PaperBirdMaster
  • 12,806
  • 9
  • 48
  • 94
  • 3
    `delete` isn't the only thing done to get rid of a pointer-like resource. You can have a custom deleter that `free`s or does other things which don't like null pointers. – Xeo Feb 06 '14 at 14:54

2 Answers2

6

Yes, the check for non-null is required by the standard (C++11, [unique.ptr.single.modifiers]§4):

void reset(pointer p = pointer()) noexcept;

4 Effects: assigns p to the stored pointer, and then if the old value of the stored pointer, old_p, was not equal to nullptr, calls get_deleter()(old_p). [ Note: The order of these operations is significant because the call to get_deleter() may destroy *this. —end note ]

(emphasis mine)

Discussion: An alternative way to standardise it would be to put the "burden" on the user of the class, i.e. require all deleters (the default one and any custom ones) to work fine when invoked on a null pointer.

However, I understand the idea was to enable functions like free() and even things like a hypothetical unlock_mutex(Mutex*) to work as deleters out-of-the-box, regardless of how/if they handle null pointers. So putting this check into the unique_ptr itself broadens the selection of deleters which can be used directly.

Community
  • 1
  • 1
Angew is no longer proud of SO
  • 167,307
  • 17
  • 350
  • 455
  • And what could be the reason to do that if deleting a null pointer have no effect? – PaperBirdMaster Feb 06 '14 at 14:55
  • 3
    @PaperBirdMaster What if the deleter is not the default deleter, and does not work with a null pointer? – Angew is no longer proud of SO Feb 06 '14 at 14:55
  • well, I wass assuming that if you create a custom deleter, that custom deleter **must** conform some conditions like *do not try to operate over a null pointer*, but obviously, that was my mistake (and I cannot found nothing about conditions/preconditios about the custom deleter, so that must be the reason :) – PaperBirdMaster Feb 06 '14 at 15:03
  • 2
    @PaperBirdMaster Yes, that would have been an alternate route for the standard to take. But I understand the idea was to enable functions like `free()` and even things like a hypothetical `unlock_mutex(Mutex*)` work as deleters out-of-the-box, so they decided to put the burden on the `unique_ptr` instead of its user. – Angew is no longer proud of SO Feb 06 '14 at 15:08
  • good point in that last comment, would you mind to include this explanation into the answer for future readers? (even after that I already accepted the answer) – PaperBirdMaster Feb 06 '14 at 15:11
  • @angew We'd had a lively discussion about this point at C++ and Beyond this year. Particularly about how the documentation about the destructor of unique_ptr has different phrasing about the nullptr case. The destructor explicitly calls out the behaviour of the nullptr case, but reset only talks about the non-nullptr case. (Well, at least in the C++14/N3797 draft). Neither actually guarantees that `get_deleter()(old_p)` is _not_ called in the nullptr case. – Andre Kostur Feb 06 '14 at 15:39
2

What if your deleter does not do a simple delete operation ? What if your unique_ptr has a custom deleter that does something else, would you like your deleter to be called with nullptr as a parameter ? :D

Drax
  • 12,682
  • 7
  • 45
  • 85
  • If I ever wanted to allow my custom deleter to be called with a null pointer: I will check the nullity into the deleter itself ;P but now I can assume that my custom deleter will not be called with `nullptr` (even if I wanted to, for some random and freaking reason) – PaperBirdMaster Feb 06 '14 at 15:09
  • 1
    @PaperBirdMaster Actually the `delete` operator checking for a null pointer is the weird guy in a language where you are not supposed to pay for something you don't use (why would i have to pay for an additional check if i never delete `nullptr` ?), but i guess for historical reasons and to mimic the behaviour of `free()` it was made to check for `nullptr` since enough coders seems to rely on this behaviour. The same custom deleter you use could also be used in another context where checking for `nullptr` doesn't make much sense, it would be sad to require a wrapper just for a null check :) – Drax Feb 06 '14 at 15:25