Does the standard behavior for deleters differ between shared_ptr and unique_ptr in the case of null pointers?
c++, c++11, nullptr, shared-ptr, unique-ptr
Solution
The observed behavior is in accordance with the standard.
For `unique_ptr`, 20.7.1.2.2/2 (destructor effects) says
Effects: If `get() == nullptr` there are no effects. Otherwise `get_deleter()(get())`.
For `shared_ptr`, 20.7.2.2.2/1 says that the deleter should be called even if it wraps the null pointer:
Effects:
- If *this is empty or shares ownership with another `shared_ptr` instance (`use_count() > 1`), there are no side effects.
- Otherwise, if *this owns an object `p` and a deleter `d`, `d(p)` is called.
- Otherwise, *this owns a pointer `p`, and `delete p` is called.
The important detail here is the expression "owns an object `p`". 20.7.2.2/1 says that "a `shared_ptr` object is empty if it does not own a pointer". 20.7.2.2.1/9 (the relevant constructor) says that it "constructs a `shared_ptr` object that owns the object `p` and the deleter `d`".
So as far as I can tell, that invocation technically makes the `shared_ptr` own the null pointer, which results in the deleter being called. Contrast this with the parameterless constructor which is said to leave the `shared_ptr` "empty".
Problem
OK, so first some things that might be relevant: I'm using the Clang 3.1 compiler, in C++11 mode, with the standard library set to libc++. I'm trying to familiarize myself with C++11, and in so doing I ran across behavior that seems odd. It may be a quirk of Clang or libc++ but I can't speak C++ standardese and I have no access to other compilers with C++11 support so I can't really check it, and I've searched the internet and Stack Overflow to the best of my ability without finding anything related...so here we go: When using shared_ptr / unique_ptr to implement RAII for a simple resource, it seems that their behavior differs with respect to null pointers upon deletion. I realize that normally it's not necessary to delete a null pointer, but I had expected the behavior to at least match between the two STL smart pointers. For the specific case, consider the following code: ``` { auto Deleter = [](void *){cout << "It's later!" << endl;}; shared_ptr<void> spDoSomethingLater(nullptr, Deleter); unique_ptr<void, void (*)(void *)> upDoSomethingLater(nullptr, Deleter); cout << "It's now!" << endl; } ``` I would have expected one of the following outputs from this: a) If both deleters are called even though the pointer is null: ``` "It's now!" "It's later!" "It's later!" ``` b) If neither deleter is called because the pointer is null: ``` "It's now!" ``` But I observe neither of these cases. Instead, I observe: ``` "It's now!" "It's later!" ``` Which means one but not the other of the deleters is being called. Upon further investigation, I found that the deleter for shared_ptr is called regardless of whether it holds a null value, but unique_ptr's deleter is only called if it does not hold a null value. My questions: Is this actually the correct behavior as specified by the standard? If so, why does the specified behavior differ between the two STL types in this manner? If not, is this a bug I should report to libc++?